在同构重做应用程序中设置cookie的位置?

我有3个关于redux和同构应用的一般问题:

  • 在客户端和服务器之间共享“运行时”数据的最佳方式是什么? 例如,当用户login远程API时,我将会话对象存储在cookie中。 这样, 下一次客户端请求我的前端时,前端服务器可以读取cookie并使用前一个会话初始化redux存储。 这样做的缺点是客户端必须在启动时(例如在根组件的componentDidMount中)validation/无效会话。 我应该请求会话服务器端,而不是从cookie中读取?
  • 我应该在哪里执行cookie存储的操作,在动作创build者还是减速器中? 我应该将cookie存储在处理用户会话的reducer中吗?
  • 我应该在哪里执行redirect用户的操作(通过react-router)? 我的意思是当我的用户login成功后,我应该从哪里发送redirect操作(一旦解决login许诺,从loginActionCreator中,在别的地方?)

提前致谢。

我设法得到一个非常整洁的应用程序结构。 这是我发现的每个问题:

  • 我只通过cookie在我的客户端和前端服务器之间共享API服务器令牌。 客户端每次请求该站点时。 前端服务器调用API服务器来validation会话。 如果这些服务器在同一个networking上,它真的很快(<5ms)。 在初始渲染之前,我还为服务器上的客户端预取了一些有用的数据。 我设法让我的应用程序加载和准备(JavaScript加载)在600毫秒的客户端。 这是相当不错的。

  • 存储cookie的行为是在我的行动创造者。 正如伊森•克拉克(Ethan Clark)所说,我们必须保持减速器纯洁 testing起来要容易得多。

  • 一旦用户通过身份validation,我仍然会在login创build者中发送redirect。 我猜测testing比在组件或其他地方的promise解决之后分派动作更容易。

事实上,牢记这一点,使我们有一个真正的应用程序很容易testing(期望的行动创造者,你必须有大量的间谍)。

希望它能帮助别人。

感谢参与。

问题2:您应该在您的操作创build者中执行存储Cookie。 减速器必须保持纯粹的function。

我真的很抱歉,我不知道1和3的答案,但我希望这有助于!

你应该把你的问题分成三个不同的堆栈溢出问题,因为它们有点不同。

我同意Ethan,你的减肥者应该是纯粹的,没有副作用。 无论如何,这就是目标(又名最佳实践)。 然而,Ben Nadel一直在探索这方面的问题,并build议创build一个工作stream程层来pipe理业务逻辑,而不是把负担放在商店上。 你应该看看他在AngularJS文章中使用Reduxpipe理本地caching数据,了解更多信息。

cookies是同步的 – 你可以水合和订阅你的商店,或者制作一个元缩减器,在减速器周围joincreateStore之前。 下面是两个简单的例子:

//first option const Cookie = require('js-cookie'); const loadState = (key) => Cookie.getJSON(key); const saveState = (nextState, key) => Cookie.set(key, nextState); const persistedState = loadState('todos'); const store = createStore( todoApp, persistedState ); store.subscribe(throttle(() => { saveState({ todos: store.getState().todos, }, 'todos'); }, 1000)); //second option - meta reducer // usage const Cookie = require('js-cookie'); export function cookieMeta ( key: string, reducer: any, expiry: Date | number = 365, path: string = '/', domain: string = window.location.hostname): Function { return function(state: any, action: any): any { let nextState = reducer(state, action); let cookieState = Cookie.getJSON(key); if (action.type.includes('DELETE')) { Cookie.remove(key); } else if (!nextState && cookieState || action.type === '@@redux/INIT') { nextState = cookieState; } else if (nextState && nextState !== cookieState) { Cookie.set(key, nextState, { expires: expiry, path: path, domain: domain, secure: process.env.local }); } return nextState; }; }; // how to implement the meta reducer import { todos } from './todos'; import { cookieMeta } from './middleware/cookieMeta'; export function TODOS_REDUCER (state: any, action: any) { return cookieMeta('todos', todos)(state, action); } export const todoApp = combineReducers({ todos: TODOS_REDUCER })