React

[TIL/React] 2023/10/17

reference: https://www.npmjs.com/package/redux-persist > Redux-Persist โœ๏ธ ๋ฐฐ๊ฒฝ ๐ŸŸ  ํ”„๋กœ์ ํŠธ ์ง„ํ–‰ ์ค‘(=์‡ผํ•‘ ์นดํŠธ ๋ชฉ๋ก ํŽ˜์ด์ง€), ์ƒˆ๋กœ๊ณ ์นจ์— ์˜ํ•ด ๋ฐ์ดํ„ฐ๊ฐ€ ์ดˆ๊ธฐํ™”๋œ๋‹ค๋Š” ๋ฌธ์ œ์ ์„ ๋ฐœ๊ฒฌํ–ˆ๋‹ค. Redux-Per

2023๋…„ 10์›” 17์ผ3min read

reference: https://www.npmjs.com/package/redux-persist

Redux-Persist โœ๏ธ

๋ฐฐ๊ฒฝ ๐ŸŸ 

ํ”„๋กœ์ ํŠธ ์ง„ํ–‰ ์ค‘(=์‡ผํ•‘ ์นดํŠธ ๋ชฉ๋ก ํŽ˜์ด์ง€), ์ƒˆ๋กœ๊ณ ์นจ์— ์˜ํ•ด ๋ฐ์ดํ„ฐ๊ฐ€ ์ดˆ๊ธฐํ™”๋œ๋‹ค๋Š” ๋ฌธ์ œ์ ์„ ๋ฐœ๊ฒฌํ–ˆ๋‹ค. Redux-Persist๋Š” ๋ธŒ๋ผ์šฐ์ €์— ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋„๋ก ๋•๋Š”๋‹ค.

์ด์ปค๋จธ์Šค ์‚ฌ์ดํŠธ์˜ '์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋ชฉ๋ก' ๋˜๋Š” '๋‹คํฌ๋ชจ๋“œ' ๋“ฑ, ์œ ์ €์˜ ๊ฐœ์ธ์ •๋ณด ์œ ์ถœ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด, ๋ธŒ๋ผ์šฐ์ €์— ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์œ ๋ฆฌํ•˜๊ฒ ๋‹ค.

๋”ฐ๋ผ์„œ ๋ณธ TIL์—์„œ๋Š” Redux-Persist๊ฐ€ ์ œ๊ณตํ•˜๋Š” API ๋ช‡ ๊ฐ€์ง€๋ฅผ ์‚ดํŽด๋ณด๊ณ  ๊ธฐ์ดˆ์ ์ธ ์‚ฌ์šฉ๋ฒ•์— ๋Œ€ํ•ด ๊ธฐ์ˆ ํ•˜๊ฒ ๋‹ค. ์ถ”๊ฐ€์ ์œผ๋กœ ์–ด์ œ๊นŒ์ง€ ์‹œ๋„ํ•œ shopping cart์— ๋Œ€ํ•œ ์ „๋ฐ˜์ ์ธ ๋กœ์ง์„ ์ •๋ฆฌํ•˜๋„๋ก ํ•˜๊ฒ ๋‹ค.

๊ตฌ์กฐ ๐ŸŸ 

code
// configureStore.js
 
import { createStore } from 'redux'
import { persistStore, persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage' // defaults to localStorage for web
 
import rootReducer from './reducers'
 
const persistConfig = {
  key: 'root',
  storage,
}
 
const persistedReducer = persistReducer(persistConfig, rootReducer)
 
export default () => {
  let store = createStore(persistedReducer)
  let persistor = persistStore(store)
  return { store, persistor }
}

์œ„ ์ฝ”๋“œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ํ”„๋กœ์ ํŠธ์˜ store.js ํŒŒ์ผ์— ์ž…๋ ฅ๋  ๋‚ด์šฉ์ด๋‹ค. API์— ๋Œ€ํ•ด์„œ๋Š” ์ฐจํ›„ ์‚ดํŽด๋ณผ ์˜ˆ์ •์ด๋‹ˆ, ๊ตฌ์กฐ๋ถ€ํ„ฐ ํ™•์ธํ•˜๊ฒ ๋‹ค.

persistConfig๋ผ๋Š” ๊ฐ์ฒด๊ฐ€ ์„ ์–ธ๋˜์–ด ์žˆ๊ณ  ๋‚ด๋ถ€์—๋Š” 'key:'root''์™€ 'storage'๊ฐ€ ์žˆ๋‹ค. ์ด ๊ฐ์ฒด๋ฅผ persistReducer๋ผ๋Š” ํ•จ์ˆ˜์— ์ฒซ ๋ฒˆ์งธ ์ธ์ž๋กœ ์ „๋‹ฌํ•˜๊ณ  ์žˆ๋‹ค. ๋‘ ๋ฒˆ์งธ ์ธ์ž์—๋Š” rootReducer๊ฐ€ ์žˆ๋‹ค.

persistReducer ํ•จ์ˆ˜๋ฅผ persistedReducer์— ์ €์žฅํ•˜๊ณ , persistedReducer๋ฅผ createStore ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด store์— ํ• ๋‹นํ•œ ๋ชจ์Šต์ด๋‹ค.

์ถ”๊ฐ€์ ์œผ๋กœ persistStore๋ผ๋Š” ํ•จ์ˆ˜์— ์œ„ store๋ฅผ ์ธ์ž๋กœ ์ „๋‹ฌํ•˜์—ฌ persistor๋ผ๋Š” ๋ณ€์ˆ˜์— ํ• ๋‹นํ–ˆ๋‹ค.

code
import { PersistGate } from 'redux-persist/integration/react'
 
// ... normal setup, create store and persistor, import components etc.
 
const App = () => {
  return (
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        <RootComponent />
      </PersistGate>
    </Provider>
  );
};

๋ฃจํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์œ„ ์ฝ”๋“œ์ฒ˜๋Ÿผ PersistGate๋กœ ๊ฐ์‹ธ๋ฉด ์ตœ์ข…์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ธŒ๋ผ์šฐ์ €์— ์ €์žฅ๋œ๋‹ค.

API ๐ŸŸ 

#### persistReducer() ๐ŸŸข

persistReducer()๋Š” ๋‘ ๊ฐœ์˜ ์ธ์ž(=config, store)๋ฅผ ๋ฐ›๋Š”๋‹ค.

config obj

config ๊ฐ์ฒด๋Š” Redux-Persist์— ๋Œ€ํ•œ ์„ค์ •์„ ํฌํ•จํ•˜๋Š” ๊ฐ์ฒด๋‹ค. key๋Š” Redux ์ƒํƒœ๋ฅผ ์‹๋ณ„ํ•  ๋•Œ ์‚ฌ์šฉํ•  key๋‹ค. storage๋Š” ์ €์žฅ์†Œ ์œ ํ˜•(=๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€, ์„ธ์…˜ ์Šคํ† ๋ฆฌ์ง€)์„ ์˜๋ฏธํ•œ๋‹ค.

localStorage์— ์ €์žฅํ•˜๊ณ  ์‹ถ์œผ๋ฉด import storage from 'redux-persist/lib/storage', session Storage์— ์ €์žฅํ•˜๊ณ  ์‹ถ์œผ๋ฉด import storageSession from 'redux-persist/lib/storage/session'๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ๋œ๋‹ค.

์š”์•ฝํ•˜์ž๋ฉด persistReducer()๋Š” Redux-Persist์— ๋Œ€ํ•œ ์„ค์ •์„ ํฌํ•จํ•˜๋Š” ๊ฐ์ฒด์ธ config๋ฅผ ์ „๋‹ฌ๋ฐ›์•„์„œ, Redux ์ƒํƒœ๋ฅผ ์ง€์†์ ์œผ๋กœ ์ €์žฅํ•˜๊ณ  ๋ณต์›ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ``์ƒˆ๋กœ์šด reducer``๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.

#### persistStore() ๐ŸŸข

persistReducer()๋ฅผ ํ†ตํ•ด persist์— ๋Œ€ํ•œ ์„ค์ •์ด ์ ์šฉ๋œ reducer๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค. persistStore()๋Š” ํ•ด๋‹น ๋‚ด์šฉ์„ ๋‹ด์•„์„œ, persist์— ๋Œ€ํ•œ ์„ค์ •์ด ``์ ์šฉ๋œ store`๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. 'persistStore(store)'๋Š” persistor `๊ฐ์ฒด``๋‹ค.

#### persistor obj ๐ŸŸข

persistor ๊ฐ์ฒด๋Š” Redux Persist์˜ persistStore ํ•จ์ˆ˜๋กœ๋ถ€ํ„ฐ ๋ฐ˜ํ™˜๋˜๋ฉฐ, ์ƒํƒœ๋ฅผ ์˜๊ตฌ์ ์œผ๋กœ ์ €์žฅํ•˜๊ณ  ๋ณต์›ํ•˜๊ธฐ ์œ„ํ•œ ์—ฌ๋Ÿฌ ์œ ์šฉํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค. purge, flush, pause, persist๊ฐ€ ์žˆ๋Š”๋ฐ ๋ณธ ๊ธ€์—์„œ๋Š” ์ž์„ธํžˆ ๋‹ค๋ฃจ์ง€ ์•Š๋„๋ก ํ•˜๊ฒ ๋‹ค. ์œ ์šฉํ•œ ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋‹ค๋Š” ์ ๋งŒ ์•Œ์•„๋‘๊ณ  ๋„˜์–ด๊ฐ€์ž.

total ๊ด€๋ จ ๋กœ์ง โœ๏ธ

code
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import { splitPrice } from "../utils/commonModule";

export const getCartData = createAsyncThunk(
  "cart/getCartData",
  async (action) => {
    console.log(action);
    try {
      return action;
    } catch (error) {
      console.error("Error: ", error);
      throw error;
    }
  }
);

export const deleteCardData = createAsyncThunk(
  "cart/deleteCardData",
  async (productId) => {
    try {
      return productId;
    } catch (error) {
      console.error("Error: ", error);
      throw error;
    }
  }
);

export const updateTotalPriceAndQuantity = createAsyncThunk(
  "cart/updateTotalPriceAndQuantity",
  async (_, { getState }) => {
    const state = getState();
    const { cartProduct } = state.cart;

    const { totalPrice, totalQuantity } = cartProduct.reduce(
      (acc, item) => {
        acc.totalPrice += splitPrice(item.price) * item.count;
        acc.totalQuantity += item.count;
        return acc;
      },
      { totalPrice: 0, totalQuantity: 0 }
    );

    return { totalPrice, totalQuantity };
  }
);

const cartSlice = createSlice({
  name: "cart",
  initialState: {
    cartProduct: [],
    totalPrice: 0,
    totalQuantity: 0,
  },
  reducers: {},
  extraReducers: (builder) => {
    builder.addCase(getCartData.fulfilled, (state, action) => {
      const { category, id, count } = action.payload;
      const existingProductIndex = state.cartProduct.findIndex(
        (product) => product.category === category && product.id === id
      );
      if (existingProductIndex !== -1) {
        state.cartProduct[existingProductIndex].count += count;
      } else {
        state.cartProduct.push(action.payload);
      }
    });

    builder.addCase(deleteCardData.fulfilled, (state, action) => {
      const { id, category } = action.payload;
      const deleteIndex = state.cartProduct.findIndex(
        (product) => product.category === category && product.id === id
      );
      if (deleteIndex !== -1) {
        state.cartProduct.splice(deleteIndex, 1);
      }
    });

    builder.addCase(updateTotalPriceAndQuantity.fulfilled, (state, action) => {
      const { totalPrice, totalQuantity } = action.payload;
      state.totalPrice = totalPrice;
      state.totalQuantity = totalQuantity;
    });
  },
});

export default cartSlice.reducer;

์ด์ œ ์ง„์งœ ์™„๋ฒฝํ•˜๊ฒŒ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ–ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋‚ด์ผ์ด ์‹œํ—˜์ด๊ธฐ์—...

view๊นŒ์ง€ ์™„๋ฒฝํ•˜๊ฒŒ ๊ตฌ์„ฑํ•ด์„œ ์ตœ์ข…์ ์œผ๋กœ ์ •๋ฆฌํ•˜๋„๋ก ํ•˜๊ฒ ๋‹ค!

More to read

AI

AI&ML ๊ธฐ์ดˆ

Reference: https&#x3A;//bettermesol.github.io/ml/2019/09/16/ai-ml-dl/AI: ๊ธฐ๊ณ„๊ฐ€ ์‚ฌ๋žŒ์ฒ˜๋Ÿผ ์ƒ๊ฐํ•˜๊ณ  ํŒ๋‹จํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฐ€์žฅ ๋„“์€ ๋ฒ”์ฃผ์˜ ๊ธฐ์ˆ ์ž…๋‹ˆ๋‹ค.ML: ๋ฐ์ดํ„ฐ๋ฅผ ํ•™์Šตํ•˜์—ฌ ์Šค์Šค๋กœ ๊ทœ์น™์„ ์ฐพ์•„๋‚ด๋Š” AI์˜ ํ•œ ๋ถ„์•ผ๋กœ,

'AI Agent Economy'

Novitas : AI Agent๊ฐ€ ์ง€๊ฐ‘์„ ๊ฐ€์ง€๋Š” ์„ธ์ƒ

์–ผ๋งˆ ์ „, ๋ฏธ๋ž˜์—์…‹์ฆ๊ถŒ ๋ฆฌ์„œ์น˜ ๋ฆฌํฌํŠธ(์˜ฌํ•ด๋Š” ์ด๋”๋ฆฌ์›€์ด๋‹ค: ์—์ด์ „ํŠธ ์‹œ๋Œ€์˜ Near Automata)๋ฅผ ์ ‘ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. AI Agent๋ฅผ ์ธ๊ฐ„๊ณผ ํ•จ๊ป˜ํ•  ๊ฒฝ์ œ ์ฃผ์ฒด๋กœ ๋ฐ”๋ผ๋ณด๋Š” ์‹œ๊ฐ์— ์ ์ž–์ด ์ถฉ๊ฒฉ์„ ๋ฐ›์•˜๋”๋žฌ์ฃ .ํ•œ ๊ฐ€์ง€ ์งš๊ณ  ๋„˜์–ด๊ฐˆ ๋ถ€๋ถ„์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ํ”ํžˆ 'AI'

'ERC-8004'

Novitas: AI ์—์ด์ „ํŠธ ๊ฒฝ์ œ ์ฃผ์ฒด

Web 4.0์„ ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์ •์˜ํ•˜๋ฉด Sovereign Transact์ž…๋‹ˆ๋‹ค.AI๊ฐ€ ์ธ๊ฐ„์˜ ํ—ˆ๋ฝ ์—†์ด ์ง€๊ฐ‘์„ ์†Œ์œ ํ•˜๊ณ , ๊ฒฐ์ œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉฐ, ์ธํ”„๋ผ๋ฅผ ํ†ต์ œํ•˜๋Š” ์ฃผ๊ถŒ์  ๊ฒฝ์ œ ์ฃผ์ฒด๊ฐ€ ๋˜๋Š” ์„ธ๊ณ„์ž…๋‹ˆ๋‹ค. Web 3.0์ด ๋ธ”๋ก์ฒด์ธ ๊ธฐ๋ฐ˜์˜ ํƒˆ์ค‘์•™ํ™”๋ฅผ ์‹คํ˜„ํ–ˆ๋‹ค๋ฉด, Web 4.0์€ ๊ทธ