LoginSignup
4
2

More than 5 years have passed since last update.

connected-react-routerとredux-persistを共存させる

Posted at

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/
でサンプル画面を表示
img_20190415.png

redux-persistがない場合の動作

Counterを表示
img_20190415_1.png
カウントを操作
img_20190415_2.png
react-router経由でページ移動した後戻った場合は状態が保存されている
img_20190415_2.png

img_20190415.png

img_20190415_2.png
ページの更新やアドレスバーを書き換えた場合状態はクリアされる
img_20190415_2.png

img_20190415_1.png

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()
  })
}

これで再度実行するとページの更新を掛けても状態が保存されている
img_20190415_2.png

img_20190415_2.png

react-routerをredux-persistから除外する

ただしこのままではreact-routerのLinkを経由しないアドレスバーからのパス入力にて
/や/helloや/counterなどを入力してページ遷移をしようとしても最後にreact-routerのLink経由で移動したページにリダイレクトされてしまう

これを回避するためには
src/configureStore.jsのpersistConfigに保存したくない要素をブラックリストとして登録する

登録する対象はブラウザのデベロッパーツールにてlocalStorageを確認すると以下の様に保存されているので
img_20190415_3.png
routerをブラックリストに登録すればよさそうである

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

これでページリロードに対して状態を保存を保持しつつアドレスバーを有効に使えるようになる

4
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2