Redux-Persist与React-Router-Redux下Query Params丢失问题求助
我之前也碰到过几乎一模一样的坑!你分析的完全没错,就是Redux-Persist在恢复持久化状态时,把routing reducer里的内容覆盖了,导致刚从URL里拿到的code参数被之前持久化的路由状态冲掉了。下面给你几个亲测有效的解决方案:
方案一:直接排除routing reducer不被持久化(最推荐)
你之前尝试过blacklist但没效果?大概率是配置位置不对。要确保把blacklist放在persist的核心配置里,修改代码如下:
const config = { key: 'root', storage, blacklist: ['routing'] // 新增这行,排除路由状态持久化 } const reducer = persistReducer(config, rootReducer)
这样Redux-Persist就不会把路由状态存在localStorage里,每次页面加载时,路由状态会直接从当前URL初始化,自然不会丢失code参数。
如果还是没生效,检查你的rootReducer里,路由对应的reducer键名是不是routing——比如用react-router-redux的routerReducer时,是不是在combineReducers里命名为routing?如果键名是router,那blacklist里就要改成['router']。
方案二:用redux-persist-transform-filter精准过滤路由状态
如果因为某些原因不能完全排除routing,可以用这个库过滤掉路由里的临时参数(比如你的code),只保留需要持久化的部分。
首先安装依赖:
npm install redux-persist-transform-filter --save
然后修改persist配置:
import createFilter from 'redux-persist-transform-filter'; // 创建过滤器,不保存routing里的任何内容(也可指定只保存特定字段) const routingFilter = createFilter( 'routing', // 目标reducer的键名 [] // 空数组表示不保存任何字段 ); const config = { key: 'root', storage, transforms: [routingFilter] // 加入过滤器 } const reducer = persistReducer(config, rootReducer)
这样即使Redux-Persist持久化了routing,也会是空状态,恢复时不会覆盖当前URL的路由参数。
方案三:手动拦截REHYDRATE动作,保留当前路由状态
如果上面两个方案都不行,还可以在rootReducer里手动处理REHYDRATE动作,强制保留当前的路由状态:
import { combineReducers } from 'redux'; import { routerReducer } from 'react-router-redux'; import { REHYDRATE } from 'redux-persist'; // 导入你的其他reducers const appReducer = combineReducers({ routing: routerReducer, // 其他reducers... }); const rootReducer = (state, action) => { if (action.type === REHYDRATE) { // 恢复持久化状态时,保留当前从URL解析的路由状态 const newState = { ...action.payload, routing: state.routing || action.payload.routing }; return appReducer(newState, action); } return appReducer(state, action); }; export default rootReducer;
这个方法的原理是,在REHYDRATE触发时,用当前已经带有code参数的路由状态,去覆盖持久化回来的旧路由状态。
额外保险:提前捕获code参数
为了万无一失,你可以在页面加载最早期就把code参数提取出来,比如在index.js创建store之前:
// 在configureStore之前解析URL const urlParams = new URLSearchParams(window.location.search); const authCode = urlParams.get('code'); // 将authCode作为初始state传入store function configureStore(initialState) { let store = createStore( reducer, initialState, compose(...) // 你的中间件配置 ) // ... } const initialState = authCode ? { auth: { code: authCode } } : {}; const { persistor, store } = configureStore(initialState);
这样即使路由状态被意外覆盖,你已经提前把code存到store里了,不会丢失。
内容的提问来源于stack exchange,提问作者RedOster

