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

connected-react-routerとredux-persistの両方を一つのプロジェクト内で共存させようとするとよく分からなくなるのでまとめ

説明のためのベースプロジェクトは
githubの[connected-react-router](https://github.com/supasate/connected-react-router)のexamples/basic/
を利用

##準備

```terminal
$ 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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314532/268408ff-3c19-f8a1-3ed7-4253c9d1396f.png)

##redux-persistがない場合の動作
Counterを表示
![img_20190415_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314532/cb32e4ac-1943-a5b4-4337-60e1f347876f.png)
カウントを操作
![img_20190415_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314532/45de0954-8c5a-601c-6909-87221d4b33a5.png)
react-router経由でページ移動した後戻った場合は状態が保存されている
![img_20190415_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314532/45de0954-8c5a-601c-6909-87221d4b33a5.png)
↓
![img_20190415.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314532/268408ff-3c19-f8a1-3ed7-4253c9d1396f.png)
↓
![img_20190415_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314532/45de0954-8c5a-601c-6909-87221d4b33a5.png)
ページの更新やアドレスバーを書き換えた場合状態はクリアされる
![img_20190415_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314532/45de0954-8c5a-601c-6909-87221d4b33a5.png)
↓
![img_20190415_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314532/cb32e4ac-1943-a5b4-4337-60e1f347876f.png)

##redux-persistを導入する

```terminal
npm install redux-persist
```
src/configureStore.jsの編集

```diff: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の編集

```diff: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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314532/45de0954-8c5a-601c-6909-87221d4b33a5.png)
↓
![img_20190415_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314532/45de0954-8c5a-601c-6909-87221d4b33a5.png)

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

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

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

登録する対象はブラウザのデベロッパーツールにてlocalStorageを確認すると以下の様に保存されているので
![img_20190415_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314532/d039b9a4-473e-ba71-cfc6-77cc8c023509.png)
routerをブラックリストに登録すればよさそうである


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

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