Redux 路由器 - 刷新后如何重播状态?

Posted

技术标签:

【中文标题】Redux 路由器 - 刷新后如何重播状态?【英文标题】:Redux router - how to replay state after refresh? 【发布时间】:2016-03-06 10:58:30 【问题描述】:

我有一个多步骤表单应用程序,我正在努力思考如何保存我的 redux 状态并在刷新后重放它?在应用程序中返回/前进按预期工作,但在浏览器刷新后,我之前的状态为空。理想情况下,我希望能够在与路径相关的会话存储中保存先前的状态,以便稍后重播,但我不知道如何轻松做到这一点。有没有人做过这样的事情并且可以提供一些指示?谢谢。

【问题讨论】:

【参考方案1】:

您似乎正在尝试在多页上下文中使用单页应用程序框架。为了使两者更好地结合在一起,您可以考虑制作自己的中间件来同步与localStorage 之间的状态,以创建一个在刷新/页面导航后似乎没有丢失任何状态的应用。

    类似于redux-logger 记录both the previous and next states 的方式,我可能首先在createStoreWithMiddleware 函数创建的开头(localStorageLoad)和结尾(localStorageDump)插入一个中间件(右之前redux-logger):
// store/configureStore.js

const createStoreWithMiddleware = applyMiddleware(
    localStorageLoad, thunk, promise, localStorageDump, logger
)(createStore);
    然后在您初始化应用时立即触发初始操作以在应用呈现之前加载存储的状态:
// index.js

const store = configureStore();

store.dispatch( type: 'INIT' );

ReactDOM.render(<App />, document.getElementById('root'));

localStorageLoad 将处理INIT 操作并调度某种SET_STATE 操作,其中将包含具有先前保存在localStorage 中的状态的有效负载。

// middleware/localStorageLoad.js

export default store => next => action => 
    const  type  = action;
    if (type === 'INIT') 
        try 
            const storedState = JSON.parse(
                localStorage.getItem('YOUR_APP_NAME')
            );
            if (storedState) 
                store.dispatch(
                    type: 'RESET_STATE',
                    payload: storedState
                );
            
            return;
         catch (e) 
            // Unable to load or parse stored state, proceed as usual
        
    

    next(action);

然后,添加一个reducer,用该有效负载替换状态,有效地像以前一样重新启动应用程序。

    要完成循环,您需要一个localStorageDump 中间件,该中间件位于将每个简化状态对象保存到localStorage 的链末尾。像这样:
// middleware/localStorageDump.js

export default store => next => action => 
    const state = store.getState();
    localStorage.setItem('YOUR_APP_NAME', JSON.stringify(state));
    next(action);

只是一个想法,还没有真正尝试过。希望这有助于您开始寻求解决方案。

【讨论】:

完美,这看起来是正确的。出于某种原因,我沉迷于使用路由而不是考虑中间件。会试一试,但无论哪种方式,它都是一个很好的起点,谢谢! 当然,祝你好运。依靠 redux 的好处是你最终得到了所有这些只是纯函数的部分。您甚至可以在将上述所有代码集成到您的应用之前轻松地对其进行单元测试。 我发现这非常有用,我从这里提出的解决方案开始实施了一些可行的方法。最终的解决方案与我认为应该分享的建议有所不同。首先,我没有使用“INIT”方法来获取初始状态。相反,我只是在创建商店时加载了初始状态。这可能违反规则,但对我来说很有意义。它本质上是代码 localStorageLoad。接下来,我使用了 sessionStorage。这是一个挑剔的,但是一旦浏览器关闭并重新启动,我宁愿重新开始。我的房间快用完了... 我确实使用了中间件概念来将状态保存到 sessionStorage,这是一个非常好的解决方案。我的设置如下所示:const middleware = applyMiddleware(..., sessionStorageSave);我的 sessionStorageSave:export default store =&gt; next =&gt; action =&gt; next(action); const state = store.getState(); let newState = ; for (var key in state) if( state.hasOwnProperty(key) ) if (state[key].toJS) newState[key] = state[key].toJS(); sessionStorage.setItem("key", JSON.stringify(newState)); 对不起,我的代码看起来很糟糕!我的代码中的关键是我必须先调用 next() 才能保存状态。这样状态会在保存之前更新。【参考方案2】:

您无法在刷新时存储状态,这是正常的。通常,您将这些存储在 cookie 或网络存储中。

Cookie 在浏览器和服务器之间同步,并在您执行的每个请求上设置。 Localstorage 为您提供最多 5MB 的空间来存储数据,并且永远不会随请求一起发送。

还原:

    填写表单时设置本地存储属性。 (完成后一定要清理干净) 使用不完整的表单刷新页面。 当 react 挂载你的Form 组件时,使用componentWillMount 方法将localstoragedispatch 的数据读取到reducer reducer 会更新 redux-state,而 redux-state 又会使用您从 localstorage 获得的属性更新组件。

如果你使用 redux 存储表单数据,则调度 localstorage 的属性。

如果不读取Form组件内部的localstorage并设置初始值。

希望这会有所帮助!

【讨论】:

我知道这是正常行为,但我希望能够将路由器更改时的 redux 状态保存到特定路由的 sessionStorage 中,然后一次性更新状态。我知道 redux-router 将路由信息保存到我的状态中,我只是希望在整个应用程序范围内而不是在组件级别。 哦,您的意思是当您在应用程序中转换到另一条路线时,您想保存未完成表单的状态?我误会了,我以为您的意思是恢复用户closed a tabrevisited 应用程序时的状态。这实际上与路由器转换无关,而是与 redux 存储的内部状态有关。你可能想看看 github.com/erikras/redux-form 这将表单状态保存在 redux 存储中。因此,即使您转换回来,除非您另有说明并传递了正确的道具,否则表单中的状态仍然是相同的。 不,基本上当用户从 A 转换到 B 时,我想存储 A 的状态,这样如果他们基于 URL 返回到 B(刷新等),就可以重新加载它.但如果可能的话,我想在整个应用程序范围内而不是每个组件上做这个应用程序。基本上是为了允许热加载,而无需重构一切以使用 webpack(目前使用 browserify)。

以上是关于Redux 路由器 - 刷新后如何重播状态?的主要内容,如果未能解决你的问题,请参考以下文章

路由器状态没有通过 redux 保持在 react-native

每次使用反应路由器导航到redux组件时,如何阻止状态存储数据在redux组件中累积

Redux:如何管理跨路由的冲突状态?

如何在不同的 URL 路由之间保存 redux 状态?

如何在不同的URL路由之间保存redux状态?

如何更新/刷新 Angular 路由器“状态”?