connected-react-router와 redux-persist를 공존시킨다

connected-react-router와 redux-persist를 하나의 프로젝트 내에서 공존시키려고 하면 잘 모르기 때문에 정리

설명을 위한 기본 프로젝트는
github connected-react-router examples/basic/
사용

준비


$ git clone https://github.com/supasate/connected-react-router.git
$ cd connected-react-router/examples/basic
$ npm install
$ npm start

http://[실행 중인 서버의 IP]:8080/
에서 샘플 화면 표시


redux-persist가 없는 경우의 동작



카운터 표시

카운트 조작

react-router를 통해 페이지 이동 후 돌아온 경우 상태가 저장됩니다.





페이지 업데이트 또는 주소 표시줄을 다시 작성하면 상태가 지워집니다.




redux-persist 소개


npm install redux-persist

src/configureStore.js 편집

src/configureStore.js
import { createBrowserHistory } from 'history'
import { applyMiddleware, compose, createStore } from 'redux'
import { routerMiddleware } from 'connected-react-router'
import createRootReducer from './reducers'

// モジュールの追加
+import { persistReducer } from 'redux-persist'
+import storage from 'redux-persist/lib/storage'

// redux-persistの設定
+const persistConfig = {
+  key: 'root',
+  storage,
+}

export const history = createBrowserHistory()

// 元のrootReducerからpersistedReducerを生成
+const persistedReducer = persistReducer(persistConfig, createRootReducer(history))

// store生成時に参照するrootReducerをpersistedReducerに差し替え
export default function configureStore(preloadedState) {
  const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
  const store = createStore(
-    createRootReducer(history),
+    persistedReducer,
    preloadedState,
    composeEnhancer(
      applyMiddleware(
        routerMiddleware(history),
      ),
    ),
  )

  // Hot reloading
  if (module.hot) {
    // Enable Webpack hot module replacement for reducers
    module.hot.accept('./reducers', () => {
      store.replaceReducer(createRootReducer(history));
    });
  }

  return store
}

src/index.js 편집

src/index.js
import { AppContainer } from 'react-hot-loader'
import { Provider } from 'react-redux'
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import configureStore, { history } from './configureStore'

// モジュールの追加
+import { persistStore } from 'redux-persist'
+import { PersistGate } from 'redux-persist/integration/react'

const store = configureStore()

// 元のstoreからpersistStoreを生成
+const pstore = persistStore(store)

// AppコンポーネントをPersistGateの配下にする
const render = () => {
  ReactDOM.render(
    <AppContainer>
      <Provider store={store}>
-        <App history={history} />
+        <PersistGate loading={<p>loading...</p>} persistor={pstore}>
+          <App history={history} />
+        </PersistGate>
      </Provider>
    </AppContainer>,
    document.getElementById('react-root')
  )
}

render()

// Hot reloading
if (module.hot) {
  // Reload components
  module.hot.accept('./App', () => {
    render()
  })
}


이제 다시 실행하면 페이지 업데이트를 걸어도 상태가 저장됩니다.




react-router를 redux-persist에서 제외



다만 이대로는 react-router의 Link를 경유하지 않는 어드레스 바로부터의 패스 입력으로
/또는/hello,/counter 등을 입력하여 페이지 전환을 시도해도 마지막으로 react-router의 Link를 통해 이동 한 페이지로 리디렉션됩니다.

이것을 피하기 위해
src/configureStore.js의 persistConfig에 저장하지 않으려는 요소를 블랙리스트로 등록

등록하는 대상은 브라우저의 개발자 툴에서 localStorage를 확인하면 다음과 같이 저장되어 있으므로

router를 블랙리스트에 등록하면 좋을 것 같습니다.

src/configureStore.js
const persistConfig = {
  key: 'root',
  storage,
+  blacklist: ['router'],
}

이제 페이지 다시로드에 대한 상태 저장을 유지하면서 주소 표시 줄을 효과적으로 사용할 수 있습니다.

좋은 웹페이지 즐겨찾기