18

我一直在使用 React+Flux 应用程序中的乐观更新,并看到了两件事:

  1. 如果用户在存在一些未完成的操作时尝试关闭窗口会发生什么。例如,在 Facebook 中,即使没有真正持久化,消息也会显示在墙上(这就是乐观更新所做的,对用户来说响应速度更快的应用程序)。但是,如果用户在墙上发帖并立即关闭应用程序(在注销或关闭窗口时),发帖可能会失败并且他不会收到警报。
  2. 我不喜欢 Stores 管理自己的实体(例如消息)的想法以及为持久消息触发的操作的情况(加载、成功、失败?)。它混合了东西。

所以我致力于此并创建一个ActionStore来管理由组件触发的操作的状态。这是源代码,这是一个现场演示。

它或多或少像这样工作:

  1. 组件层次结构的根(redux 中的容器)获取新操作的 nextId 并将其像道具一样传递给他的孩子(这很难看)。
  2. 子组件触发一个动作:它保留 actionId 以便在之后向商店询问它并调用动作创建者。
  3. 动作创建者创建一个新动作并向中间件返回一个函数。
  4. 从 Action 返回的函数使用 API 调用创建一个新的 Promise 并调度一个 XX_START 类型的操作。
  5. ActionStore 监听 XX_START 动作并保存它。
  6. 子组件接收新状态并找到保存的 id 的操作并询问当前情况:加载、成功或失败。

我这样做主要是为了将“实体”的状态与动作的状态分开,但也允许使用相同的有效负载重新触发动作(如果服务器暂时关闭或如果我们收到 500 响应状态,这可能很有用用户松动信号)。

此外,拥有动作存储可以在用户注销或关闭窗口之前轻松询问它们是否是待处理的动作。

注意:我正在使用针对 Rest API 的单个应用程序页面 Web 应用程序,我不认为在服务器端渲染中使用它

创建一个 ActionStore 是一个可行的选择,还是我打破了一些 Redux/Flux 基础?这可能会结束使用 React 热重载和时间旅行的可能性吗?

你应该毫不留情地回答,我可能做过很多丑陋的事情,但我正在学习 React/Redux。

4

1 回答 1

24

对于可能有点困惑的未来读者:我们不再称这些函数为“存储”:我们称它们为reducers。所以问题是关于一个reducer记住动作

我个人不喜欢你在那里建议的方法。您正在将逻辑付诸行动并为此使用继承。相反,Redux 规定动作是没有逻辑的普通对象。他们不应该“知道”如何更新一些状态,也不应该持有它——相反,他们应该描述发生了什么。

我认为在 Redux 中实现乐观更新的方法类似于在 Redux 中实现 Undo 的方式,而后者又受到Elm 架构的启发。这个想法是你应该编写一个函数,它接受一个 reducer(和一些选项)并返回一个 reducer:

function optimistic(reducer) {
  return function (state, action) {
    // do something?
    return reducer(state, action);
  }
}

您可以像使用普通减速器一样使用它:

export default combineReducers({
  something: optimistic(something) // wrap "something" reducer
})

现在它只是将状态和动作传递给reducer它包装的,但它也可以“记住”动作:

function optimistic(reducer) {
  return function (state = { history: [] }, action) {
    // do something with history?
    return {
      history: [...state.history, action],
      present: reducer(state.history[state.history.length - 1], action)
    };
  }
}

history现在它积累了该领域的所有行动。

同样,这本身并不是很有用,但您可能会看到如何实现这样的高阶 reducer:

  • 通过 ID 跟踪待处理的异步操作,并在看到带有status: 'request';的操作时开始记录历史记录
  • 当它收到带有 的动作时status: 'done',重置历史记录;
  • 当它收到一个带有 的动作时status: 'fail',调整历史以不包括初始动作status: 'request'重新运行减速器以重新计算当前状态,就好像请求从未发生过一样。

当然我没有提供实现,但这应该让您了解如何以 Redux 方式实现乐观更新。

更新:根据 OP 的评论,redux-optimist似乎正是这样做的。

于 2015-10-03T12:41:17.607 回答