[리액트] redux-persist, 새로고침해도 state를 유지시키는 방법

Date:     Updated:

카테고리:

태그:

🚀Introduction

온라인 그림판에서 작업을 하다 새로고침을 누르면 어떻게 될까? 모든것이 없어진다. 웹앱에서 새로고침을 하게되면 어떻게 될까? 모든것이 날아간다.

입력하기

배송지를 입력하다 새로고침이 되서 날아가면? 사이트 새로고침시 로그인정보가 날아가버리면? 장바구니에 담아둔 14가지 식재료들이 없어진다면??

여러가지 이유로 local storage와 session storage를 사용한다. 그렇다면 redux-persist를 이용하여 간단하게 이를 활용하는 방법을 알아보도록 하겠다

🚀기본사용법

⭐️1. persistReducer로 묶어준다

const persistedReducer = persistReducer(persistConfig, rootReducer);

⭐️2. configuration을 설정해준다

const persistConfig = {
  key: "root",
  storage,
};

⭐️3. 스토어를 만들어준다

export const store = createStore(
  persistedReducer,
  composeEnhancers(applyMiddleware())
);

⭐️4. App.js에 달아준다.

const persistor = persistStore(store);

<PersistGate loading={<Loading />} persistor={persistor}>
  <App/>
</PersistGate>  

뭔가 간단해 보이는데 막상 해보려고 하면 생각보다 꼬이는게 많다. 실제로 친구와 나는 각기 다른 프로젝트에서 redux-persist를 달아주는데 뜻대로 작동하지 않아 고생을 했다. 한번 도식도로 알아보자


🚀한눈에 보기

도식도

🚀작동

이렇게 만들게 되면, 아래와 새로고침을 해도 작업 정보들이 persist하도록 작동한다. 해당 코드는 여기에서 확인할 수 있다.


🚀깊이 알아보기1 - 원하는 store만 persist시키기

whiteList

유저스토어, 메모스토어, 환자스토어, 의사스토어 중… 메모와 유저 스토어만 영속성을 주고싶다면?(persist한 상태를 만들고 싶다면?)

const persistConfig = {
  key: "root",
  storage,
  whitelist: ["memo", "user"], // user와 settings 상태만 영속화
};

그런데 생각해보니, 유저와 메모에 대한 영속성이 필요한게 아니라 환자와 의사는 영속성을 가질 필요가 없는 상황이였다면 어떻게 해야할까? 공식문서에서도 slice API에 redux-persist를 사용하는것을 권장하지 않는다고 적혀있다. 이게 무슨뜻일까? API를 통해 가져오는 정보들을 persist시켜두면 최신정보가 아닌 정보를 화면에 보여주게 될 위험이 있으므로, API같은거는 그냥 persist시키지 말고 그때그때 불러서 쓰라는 뜻이고, 높은 확률로 client에서 저장해두었을 정보들(장바구니, 배송지 주소입력 등)을 담고있는 slice들만 persist시키라는 뜻이다.

그럼 원론으로 돌아와서, persist시키지 않을 slice들은 어떻게 처리할까? 아까와 비슷하다. 병원에서 새로들어온 최신 환자들의 정보들은 다시 API로 fetch해와야지, persist하면 안된다고 생각하여 다음과 같은 로직을 적용시켰다.

const persistConfig = {
  key: "root",
  storage,
  blacklist: ["doctor", "patient"], // user와 settings 상태만 영속화
};

이와같은 방식으로 원하는 슬라이스들의 정보를 로컬스토리지, 세션스토리지에 저장해두고, rehydration시킬 수 있는 것이다.

rehydration? 아마 next를 공부해보신 분들은 해당 뜻에 대해 유추를 해볼 수 있을 것이다.


🚀깊이 알아보기2-rehydration

왜 hydration이고 왜 rehydration일까? hydration에 대한 사전적 정의는 다음과 같다

naver사전

next를 쓰면, 클라이언트 컴포넌트로 만들어 둔 부분에 서버 컴포넌트들이 알아서 쑉쑉 자리를 차지해서 들어오고 의미있는 화면이 완성된다.

watering

정해진 위치의 화분에 물을 주면 꽃피어나서 의미있는 식물이 되듯, hydration(물이 흘러들어가듯)이 본연의 위치에 흘러들어가고 컴포넌트들이 채워지는 과정인 것이다.

이렇듯, next에서는 이 “물”이 컴포넌트단위인 것이다. 하지만, redux-persist에서는 이 “물”이라는건 state고, state의 값들이 본연의 위치로 흘러들어가는 것이 hydration과정인 것이다. 이 hydration과정에서의 “물”, 즉 state의 값들은 사실… state가 원래 가지고 있던 값이고, " state => 저장소 => (새로고침 이후)state " 의 과정을 통해 다시 자기자리로 값들이 흘러들어오는 과정이기 때문에 rehydration 이라는 이름이 붙은 것이다.


🚀깊이 알아보기3-커스텀 storage

우리는 어디에 저장할 수 있을까? local storage에 저장 할 수도 있으며, session storage에 저장 할 수도 있다.

storage설정

위 그림에서 보듯 storage를 적절하게 설정해주었으며, 이 때 local storagesession storage를 선택해줄 수 있다. 그리고 custom storage를 넣어줄 수도 있다.

//step1 커스텀 저장소 생성
const customStorage = {
  setItem: async (key, value) => {
    // 데이터 저장 로직
  },
  getItem: async (key) => {
    // 데이터 불러오기 로직
    return value;
  },
  removeItem: async (key) => {
    // 데이터 삭제 로직
  },
  getAllKeys: async () => {
    // 모든 키 불러오기 로직
    return keys;
  },
};

//step2 설정값 넣어주기
const persistConfig = {
  key: "root",
  storage: customStorage,
};

위처럼 원하는 로직을 작성하고 아까처럼 넣어주면 된다.

필자의 경우 iDB를 이용해서 클라이언트에 DB를 custom Storage로 만들어주었다. 아까보다 훨~ 빨라진 것 같다.

custom Storage를 이용한 코드가 궁금하면 여기 를 들어가면 볼 수 있다. customPersist브랜치/src/customPersist.ts로 들어가면 iDB를 이용해 커스텀 스토리지를 만든 코드를 볼 수 있다.


요약 및 정리

우리는 redux-custom persist에 대해 알아보았다. local storage혹은 session storage에 데이터들을 쉽게 저장하고 불러들여올 수 있는 유익한 라이브러리다. 공식문서에서도 API 슬라이스에 대해서는 적용하지 않기를 권장하며, 생각해보면 최신정보는 그냥 fetch해서 가져오면 된다는 것을 쉽게 떠올릴 수 있다. 이를 위해 whiteListblackList를 통해 슬라이스들에 대해 선택적으로 persist를 적용하는 방법을 알아보았다. 이처럼 사용자가 입력한 소중한 정보들을 state에저장한 뒤, 이를 storage에 저장하고, (새로고침 등 이후)다시 state로 rehydrate 할 수 있다는 사실을 알게되었다. 또한 custom Storage를 활용하여 우리가 원하는 형태로 값을 가공하여 rehydrate시킬 수 있다는 것을 알게 되었다.

(+ 혹시 작동에 대해 궁금한 부분이 있으면 작동영상, 혹은 첨부한 (깃헙의)코드들을 보며 추가적으로 궁금한 부분이 있다면 댓글로 달아주면 감사하겠습니다.)


맨 위로 이동하기

react 카테고리 내 다른 글 보러가기

댓글 남기기