redux persist

이수연·2023년 6월 6일
2

쇼핑몰 프로젝트때 모든 페이지에서 글자만 바뀌는 nav 공통 컴포넌트를 페이지 이동 할때마다 리덕스로 파라미터값을 받아와 렌더링했으나, 페이지 리로드시 리덕스의 상태값이 날라가는 이슈가 발생하여, 로컬스트리지에 redux의 상태값을 저장하여 사용할수 있도록 로직을 변경하게 되었다.

리덕스를 사용했을때의 문제점?

  1. 리덕스는 일시적인 상태 관리를 위한 라이브러리 이다. 따라서 페이지 리로드 후에는 상태값이 보존이 안되기 때문에 상태를 영구적으로 유지하기 위해서는 상태를 서버에 저장하고, 페이지 로드 시에 서버에서 상태를 복원하는 로직을 생각해야 된다.
    ex) 로컬스트리지, 세션 스토리지, 쿠키, 또는 외부 데이터베이스를 활용

  2. 리덕스는 클라이언트 측에서 상태를 관리하므로 페이지 리로드 시 이전 상태가 유지되지 않는다. 웹 애플리케이션은 HTTP 프로토콜을 기반으로 동작하며, 각 요청과 응답은 독립적 이다. 따라서 페이지 리로드 시에는 새로운 HTTP 요청이 발생하고, 이전 상태 정보가 서버에 저장되지 않은 상태로 초기화 된다.

초기 로직 설계의 문제점

초기에 로직 설계시 전역적으로 상태값을 사용할수 있으며, 자식 컴포넌트에서 상태값이 변경되어도 부모 컴포넌트에서 리렌더링이 발생되지 않는 flux 패턴의 이점이 있는 리덕스를 세팅 하게 되었다. 하지만 새로고침 이슈에대해서는 생각하지 못하였고, 페이지 로드 시에 서버에서 상태를 복원하는 로직으로 다시 생각하게 되었다. 해당 이슈를 해결하기 위하여 공부한 결과 리덕스 persist가 새로고침시에도 로컬스트리지나 세션스트리지에 저장되기 때문에 문제를 해결 할수 있다고 생각했다. But!! 여기서 한번더 우려되었던점은 중요한 정보는 로컬스트리지에 저장 되면 안된다는점 이었다. 로컬스트리지는 누구나 확인할수 있기 때문에, 유저정보와 같은 중요한 정보는 로컬 스트리지에 저장하면 안되기 때문에, 유저정보와 관련된 slice는 저장이 안되도록 세팅이 필요했다. 다행이 공식문서에 해당 이슈에 대한 설명이 기재 되있었고, black List라는 속성을 활용하여 로컬이나 세션 스토리지에 저장 되면 안되는 리스트를 따로 세팅 하여 해결 할수 있었다.

리덕스 persist란?

앞전에 문제를 제기했던 리덕스의 단점으로 인해 리덕스 persist를 공부하고 세팅하게 되었다. 리덕스 persist란 페이지 새로고침시 상태값이 유지되지 않는 리덕스의 단점을 보완할수 있게끔 localstorage나 sessionstorage에 저장할수 있는 라이브러리 입니다.

설치

npm i redux-persist

사용법은 아래와 같습니다.

  1. persistConfig에 localStorage에 저장되는 key값, 저장되는 스토리지 정보, 스토리지에 담기면 안되는 중요한 리듀서를 세팅할수 있는 blacklist(반대의 개념은 whitelist) 세팅 등등 세팅하고 싶은 값을 세팅합니다.

  2. persistReducer를 import하여 첫번째 매개변수에는 처음에 세팅한 config정보를, 두번째 매개변수에는 리듀서를 세팅한후, persistStore도 import 한후 store를 감쌉니다.

  3. 두번째 코드에 나와있듯이, PersistGate로 감싸줍니다. 이유는 지속적인 중복된 상태값이 저장되지 않도록 앱의 UI 렌더링을 지연시키도록 합니다.

store.jsx


import { combineReducers, configureStore } from "@reduxjs/toolkit";
import { persistReducer } from "redux-persist";
import pageTitleReducer from "slice/PageSlice";
import DetailReducer from "slice/DetailSlice";
import UserAddressReducer from "slice/UserAddressSlice";
import OrderListReducer from "slice/OrderSlice";
import CartItemReducer from "slice/CartSlice";
import UserInfoReducer from "slice/UserSlice";
import storage from "redux-persist/lib/storage";
import persistStore from "redux-persist/es/persistStore";

// config 작성
const persistConfig = {
  key: "root", // localStorage key
  storage, // localStorage
  blacklist: ["UserInfoReducer", UserAddressReducer],
};

export const rootReducer = combineReducers({
  pageTitleReducer,
  DetailReducer,
  UserAddressReducer,
  OrderListReducer,
  CartItemReducer,
  UserInfoReducer,
});

const persistedReducer = persistReducer(persistConfig, rootReducer);
const store = configureStore({
  reducer: persistedReducer,
});
export const persistor = persistStore(store);

export default store;

index.jsx


import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import { PersistGate } from "redux-persist/integration/react";
import { BrowserRouter } from "react-router-dom";
import { Provider } from "react-redux";
import { setUserInfo } from "slice/UserSlice";
import { decodeToken } from "react-jwt";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import store, { persistor } from "./store/store";

const root = ReactDOM.createRoot(document.getElementById("root"));
if (localStorage.jwtToken) {
  store.dispatch(setUserInfo(decodeToken(localStorage.jwtToken)));
}
// eslint-disable-next-line dot-notation
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        <BrowserRouter>
          <App />
        </BrowserRouter>
      </PersistGate>
    </Provider>
  </React.StrictMode>
);


위와 같은 작업을 수행하면, 다음과 같이 로컬스트리지에 저장이 됩니다.

참고 문헌
npm redux persist
https://www.npmjs.com/package/redux-persist#basic-usage

0개의 댓글