[TIL/React] 2023/10/17

원민관·2023λ…„ 10μ›” 17일
0

[TIL]

λͺ©λ‘ 보기
126/159

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

Redux-Persist ✍️

배경 🟠

ν”„λ‘œμ νŠΈ 진행 쀑(=μ‡Όν•‘ 카트 λͺ©λ‘ νŽ˜μ΄μ§€), μƒˆλ‘œκ³ μΉ¨μ— μ˜ν•΄ 데이터가 μ΄ˆκΈ°ν™”λœλ‹€λŠ” λ¬Έμ œμ μ„ λ°œκ²¬ν–ˆλ‹€. Redux-PersistλŠ” λΈŒλΌμš°μ €μ— 데이터λ₯Ό μ €μž₯ν•  수 μžˆλ„λ‘ λ•λŠ”λ‹€.

이컀머슀 μ‚¬μ΄νŠΈμ˜ 'μž₯λ°”κ΅¬λ‹ˆ λͺ©λ‘' λ˜λŠ” '닀크λͺ¨λ“œ' λ“±, μœ μ €μ˜ κ°œμΈμ •λ³΄ μœ μΆœμ— 영ν–₯을 λ―ΈμΉ˜λŠ” 데이터가 μ•„λ‹ˆλΌλ©΄, λΈŒλΌμš°μ €μ— ν•΄λ‹Ή 데이터λ₯Ό μ €μž₯ν•˜μ—¬ μ‚¬μš©ν•˜λŠ” 것이 더 μœ λ¦¬ν•˜κ² λ‹€.

λ”°λΌμ„œ λ³Έ TILμ—μ„œλŠ” Redux-Persistκ°€ μ œκ³΅ν•˜λŠ” API λͺ‡ 가지λ₯Ό μ‚΄νŽ΄λ³΄κ³  기초적인 μ‚¬μš©λ²•μ— λŒ€ν•΄ κΈ°μˆ ν•˜κ² λ‹€. μΆ”κ°€μ μœΌλ‘œ μ–΄μ œκΉŒμ§€ μ‹œλ„ν•œ shopping cart에 λŒ€ν•œ μ „λ°˜μ μΈ λ‘œμ§μ„ μ •λ¦¬ν•˜λ„λ‘ ν•˜κ² λ‹€.

ꡬ쑰 🟠

// 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λΌλŠ” λ³€μˆ˜μ— ν• λ‹Ήν–ˆλ‹€.

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 κ΄€λ ¨ 둜직 ✍️

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κΉŒμ§€ μ™„λ²½ν•˜κ²Œ κ΅¬μ„±ν•΄μ„œ μ΅œμ’…μ μœΌλ‘œ μ •λ¦¬ν•˜λ„λ‘ ν•˜κ² λ‹€!

profile
Write a little every day, without hope, without despair ✍️

0개의 λŒ“κΈ€