관리 메뉴

꿈꾸는 개발자

redux-persist 사용하기 본문

기타

redux-persist 사용하기

rickysin 2023. 5. 5. 20:44

redux-toolkit을 사용하다보면 가장 큰 단점이 새로고침을 했을 때 상태들이 초기화된 다는 것이다. plain JS에선 localstorage에 저장해서 상태를 유지할 수 있지만, redux에서 굳이 상태를 유지하기 위해 모든 상태를 일일이 다 localstorage 저장하는 것은 너무 힘들어 보인다....이런 문제를 간편하게 해결할 수 있는 것이 redux-persist이다

 

먼저 redux-persist를 사용하기 위해선 따로 redux-persist를 설치해줘야 한다

npm i redux-persist

사용법

redux-persist는 localstorage 뿐만 아니라, session storage, async storage 등 종류에 따른 storage를 제공한다. 하지만 본 글에서 주로 살펴볼 것은 localstorage이다. 

//store

import { configureStore, combineReducers } from '@reduxjs/toolkit';
import themeReducer from '../store/slice/themeSlice';
import { persistReducer, FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER } from 'redux-persist';
import storage from 'redux-persist/lib/storage';

// reducer를 여기에 추가하시면 됩니다
const rootReducer = combineReducers({
  theme: themeReducer,
});
// storage에 저장하기 위해 아래와 같이 persistConfig를 생성해야 한다.
const persistConfig = {
  //obj의 key를 나타냄
  key: 'root',
  //storage의 타입을 나타냄(여기에선 localstorage)
  storage,
  // theme Reducer만 persist 적용하기 whitelist 외에도 blacklist 등 여러 option이 존재한다.
  whitelist: ['theme'],
};

//enhanced된 reducer를 반환한다.(redux-persist+redux 모듈을 종합하여 persist를 반환)
const persistedReducer = persistReducer(persistConfig, rootReducer);

const store = configureStore({
  reducer: persistedReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
      },
    }),
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
export default store;

우선 모든 storage들이 persist에 전달될 수 있도록 combineReducers로 reducer들을 병합하는 작업이 필요하다. 비록 위의 예시는 하나의 reducer 밖에 없지만 향후에 추가될 reducer도 동일하게 persist를 적용하기 위해선 사전에 combineReducer를 적용하는 것이 바람직하다. 

storage 부분의 주석에서도 나타내고 있지만 localStorage를 사용할 것이기 때문에 storage를 import 했지만, 만약에 다른 형태 예로 들어서 sessionStorage를 사용하고 싶을 경우 

  • import storageSession from 'redux-persist/lib/storage/session

위와 같이 StorageSession을 import 후 storage가 위치한 자리를 대체시키면 된다.

 

그렇다면 저 middleware와 더불어 FLUSH 등 알 수 없는 것들은 왜 필요한가 싶을 수 있다. 

redux-toolkit/redux의 경우 action에 직열화가 불가능한 데이터는 넣을 수 없다. 공식문서에 따르면 serializability dev check middleware 가 직렬화가 불가능한 데이터가 payload에 있을 경우 경고를 보낸다는 것! 위 에러는 바로 직렬화의 문제로 발생한 것이다.  문서에도 언급돼 있지만 redux-persist를 사용할 경우 위의 FLUSH 등과 같은 코드+middleware를 추가해줌으로써 dispatch 의 모든 action type을 무시해줘야 한다.  그러면 위 에러는 더 이상 뜨지 않게 된다.

 

추가적으로 특정한 경우에(로그아웃 했을 때 상태 유지를 변경하고 싶을 경우) 아래와 같은 추가적인 미들웨어를 통해 조작해줄 수도 있다 로그아웃 시 모든 상태?를 지울 수도 있는 것 같다.

import { PURGE } from "redux-persist";

...
extraReducers: (builder) => {
    builder.addCase(PURGE, (state) => {
        customEntityAdapter.removeAll(state);
    });
}

적용하기

// index.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

// redux
import { Provider } from 'react-redux';
import store from './store';
import { PersistGate } from 'redux-persist/integration/react';
import { persistStore } from 'redux-persist';

const persistor = persistStore(store);

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        <App />
      </PersistGate>
    </Provider>
  </React.StrictMode>,
);

마지막으로 react-redux에서 Provider에서 하는 것처럼 전체 app에 redux-persist를 적용해야 한다. 그럴 때 위와 같이 PersistGate 컴포넌트를 사용하면 된다.

  • PersistGate의 경우 persist된 state가 적용?회수? 될 때까지 app의 rendering을 늦춰준다.
  • loading: UI 지연 시간을 지정할 수 있다. 특정 값을 줄 수 있고/null/<Loading/>과 같은 react 컴포넌트도 전달 할 수 있는 것으로 나온다.

새로고침을 하더라도 state들이 유지되는 것을 확인할 수 있다.


참고 자료

https://redux-toolkit.js.org/usage/usage-guide#working-with-non-serializable-data

 

Usage Guide | Redux Toolkit

 

redux-toolkit.js.org

참고한 자료: 

https://kyounghwan01.github.io/blog/React/redux/redux-persist/#reducer%E1%84%8B%E1%85%A6-persist-store-%E1%84%8C%E1%85%A5%E1%86%BC%E1%84%8B%E1%85%B4

 

react-redux 사용법, redux, react, react16, state management, flux, store, reducer, dispatch, action

react-redux 사용법, redux, react, react16, state management, flux, store, reducer, dispatch, action

kyounghwan01.github.io

https://dev.to/dawnind/persist-redux-state-with-redux-persist-3k0d#:~:text=redux%2Dpersist%20provides%20different%20storage,it%20to%20the%20redux%2Dpersist.

 

Persist Redux State with redux-persist

When we refresh page in a web-app, the state always resets back to the initial values which in not a...

dev.to

 

https://github.com/rt2zz/redux-persist

 

GitHub - rt2zz/redux-persist: persist and rehydrate a redux store

persist and rehydrate a redux store. Contribute to rt2zz/redux-persist development by creating an account on GitHub.

github.com