在同构Redux应用程序中,应该把cookie设置在哪里?

15
我有三个关于Redux和同构应用的一般问题:
  • 在客户端和服务器之间共享“运行时”数据的最佳方法是什么? 例如,当用户登录远程API时,我将会话对象存储在cookie中。这样,下次客户端请求我的前端时,前端服务器可以读取cookie并使用先前的会话初始化redux存储。这种方法的缺点是客户端必须在启动时验证/无效化会话(例如,在根组件的componentDidMount中)。我是否应该从服务器端请求会话而不是从cookie中读取它?
  • 应该在操作创建者或规约器中执行cookie存储操作吗? 应该将cookie存储在处理用户会话的规约器中吗?
  • 在哪里执行重定向用户的操作(通过React-router)? 我的意思是,当我的用户成功登录时,我应该从哪里调度重定向操作(从loginActionCreator一旦登录承诺已解决?还是其他地方?)

提前致谢。

4个回答

6

我成功创建了一个非常整洁的应用程序结构。

  • 我只通过cookie在客户端和前端服务器之间共享API服务器令牌。每次客户端请求站点时,前端服务器调用API服务器来验证会话。如果这些服务器在同一个网络上,则速度非常快(<5ms)。在初始渲染之前,我在服务器上为客户端预取了一些有用的数据。我成功让我的应用程序在客户端中加载并准备(javascript已加载),用时600ms,效果相当不错。

  • 存储cookie的操作在我的actions creator中进行。正如Ethan Clark所说,我们必须保持reducers的纯净。这样更容易测试。

  • 一旦用户被认证,我仍然在我的登录创建者(signin creator)中分发重定向。我想这比在组件或其他地方的promise解决后再分发动作要容易测试。

事实上,记住这一点使我们能够拥有一个非常易于测试的应用程序(除了actions creator,你必须有很多间谍)。

希望这能帮助到有需要的人。

感谢参与。


1
你有GitHub仓库或者这方面的例子吗? - j_d

4

问题 2:您应该在动作创建函数中执行 cookie 存储。Reducers 必须保持纯函数。

非常抱歉我不知道问题 1 和 3 的答案,但希望这有所帮助!


谢谢您的回答。您有解释原因的链接吗? - Cnode
1
我认为这是因为reducers需要保持同步。我找不到我读过的原始帖子,但这个链接涉及到了它:https://github.com/rackt/redux/issues/291 - Ethan Clark

2
您的问题可能应该分成三个不同的堆栈溢出问题,因为它们都有点不同。
我同意Ethan的观点,您的reducers应该是纯函数,没有副作用。这是目标(也就是最佳实践)的做法。然而,Ben Nadel一直在探索类似的问题,并建议创建一个工作流层来管理业务逻辑,而不是把这个负担放在store上。您应该查看他的Managing Locally Cached Data with Redux in AngularJS文章以获取更多信息。

谢谢你的回答。我阅读了Ethan Clark的链接,发现非常有趣。我已经将所有副作用从我的reducers中移除,并将它们放在我的action creators中。我打算阅读你的文章,并将我的问题分成3个Stack Overflow问题。 - Cnode

0

Cookies 是同步的 - 您可以将其注水并订阅您的 store,或者创建一个元 reducer,它包装了 reducer 并在添加到 createStore 之前使用。以下是两者的快速示例:

//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  })

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接