소개.
React Native로 Bitfolio 앱을 만들면서 redux 상태 관리 라이브러리를 사용하게 되어 redux-persist까지 도입하게 된 배경과 적용법까지 포스팅해 보겠습니다.
도입하게 된 배경.
redux의 store는 새로고침하거나, 앱을 재실행하면 state가 초기화됩니다.
하지만 상황에 따라 state의 초기화를 원치 않을 경우가 생길 수 있습니다.
예). 1. 다크 / 라이트 모드를 지원할 경우 사용자가 원하는 모드를 저장해야 할 경우.
2. 여러 개의 언어를 지원할 경우 사용자가 설정한 언어를 저장해야 할 경우.
3. 쇼핑몰 앱의 경우 비 로그인 주문 시 장바구니에 물건을 담을 경우.
주로 이와 같은 데이터는 React Native의 문서에 따르면 AsyncStorage에 LocalStorage 대신 저장하게 됩니다.
따라서 redux를 사용하고 있는 입장에서 데이터 관리를 통일성 있게 해주기 위해 redux-persist에 storage는 AsyncStorage로 적용하게 되었습니다.
이것으로 일반적인 redux의 상태 관리에도 앱을 닫았다 실행할 경우 데이터가 유지되는 기능을 구현할 수 있었습니다.
Package Dependencies.
npm install react-redux
npm install redux-persist
npm install @reduxjs/toolkit
npm install @react-native-async-storage/async-storage
npm install -D @types/react-redux
redux-persist 적용.
1. reducer와 persist store 정의.
// src/store/reducers.ts
import baseSettingReducer from './slices/baseSetting';
export interface ApplicationState {
baseSetting: ReturnType<typeof baseSettingReducer>;
}
const reducers = {
baseSettingReducer,
};
export default reducers;
reducer가 많아질 것을 대비하여 reducer를 하나의 객체로 묶어 export하는 파일을 별도로 만들어주겠습니다.
// src/store/index.ts
import { combineReducers } from 'redux';
import { configureStore } from '@reduxjs/toolkit';
import {
persistStore,
persistReducer,
PersistConfig,
} from 'redux-persist';
import AsyncStorage from '@react-native-async-storage/async-storage';
import reducers from './reducers';
const rootReducer = combineReducers({ ...reducers });
type ReducersState = ReturnType<typeof rootReducer>;
const persistConfig: PersistConfig<ReducersState> = {
key: 'root', // 이 key는 저장되는 값에 대한 식별자로 반드시 입력해주세요.
// persist store의 storage로 AsyncStorage를 이용하겠습니다.
// redux-persist에 내장되어 있는 localstorage 또는 sessionStorage를 import해 사용 할 수도 있습니다.
// 반드시 storage를 입력해 주어야 합니다.
storage: AsyncStorage,
whitelist: ['baseSettingReducer'], // persist store에 저장 할 reducer들
blacklist: ['globalStateReducer'], // persist store에 저장하지 않을 reducer들
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
const store = configureStore({
reducer: persistedReducer
});
const persistor = persistStore(store);
export { store, persistor };
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
persist store의 storage로 주석 설명과 같이 AssyncStorage 뿐만 아니라 LocalStorage, SessionStorage 또한 사용할 수 있습니다.
1. LocalStorage 사용의 경우 import storage from 'redux-persist/lib/storage 를 통해 사용할 수 있습니다.
2. SessionStorage 사용의 경우 import storageSession from 'redux-persist/lib/storage/session을 통해 사용할 수 있습니다.
위와 같이 redux-toolkit까지 적용한 redux persist 구성 완료되었습니다.
이제 store에 접근할 수 있도록 Root Component에 store provider를 래핑해 주겠습니다.
2. store Provider와 persistGate 래핑.
// src/App.ts
import React from 'react';
import { Provider } from 'react-redux';
import { Text } from 'react-native';
import { PersistGate } from 'redux-persist/integration/react';
import { store, persistor } from '/store';
import RootNavigation from '/navigators/Root';
const LoadingView = () => <Text>Loading...</Text>
function App() {
return (
<Provider store={store}>
<PersistGate loading={LoadingView} persistor={persistor}>
<RootNavigation />
</PersistGate>
</Provider>
);
}
export default App;
Provider 외에도 React 또는 React-Native를 사용하는 경우 Root Component를 PersistGate로 래핑해 주어야 합니다.
문서에 따르면 PersistGate는 redux에 persisted state가 저장될 때까지 앱 UI 렌더링을 지연시켜주는 역할을 한다고 합니다.
지연되는 동안 loading props의 component가 render 됩니다.
이렇게 redux-persist에 AsyncStorage를 결합한 구성과 redux toolkit 적용까지 끝마쳤습니다.
하지만 프로젝트를 진행하다 보면 persisted state들의 기본값을 바꾸거나 { key: value }를 추가, 제거해야 하는 경우가 생길 수 있습니다.
이럴 때 redux-persist를 migration 해주어야 하는데 이 내용은 다음 포스터에서 소개하겠습니다.
'사이드 프로젝트 > Bitfolio' 카테고리의 다른 글
redux-persist states migration하기. (0) | 2022.03.09 |
---|---|
사이드 프로젝트로 앱 주제 선정하기. (0) | 2022.01.12 |