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がない場合の動作
Counterを表示
カウントを操作
react-router経由でページ移動した後戻った場合は状態が保存されている
↓
↓
ページの更新やアドレスバーを書き換えた場合状態はクリアされる
↓
##redux-persistを導入する
npm install redux-persist
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の編集
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をブラックリストに登録すればよさそうである
const persistConfig = {
key: 'root',
storage,
+ blacklist: ['router'],
}
これでページリロードに対して状態を保存を保持しつつアドレスバーを有効に使えるようになる