【发布时间】:2023-04-03 14:05:01
【问题描述】:
我目前遇到需要连续运行 Redux Actions 的情况。我已经查看了各种中间件,例如 redux-promise,这似乎很好 如果你知道在根点处的连续动作是什么(因为没有更好的术语)动作被触发 。
基本上,我想维护一个可以随时添加到的操作队列。每个对象在其状态中都有一个此队列的实例,并且相关的操作可以相应地入队、处理和出队。我有一个实现,但这样做时我在我的动作创建者中访问状态,这感觉像是一种反模式。
我将尝试提供一些有关用例和实现的背景信息。
用例
假设您想创建一些列表并将它们保存在服务器上。在创建列表时,服务器会使用该列表的 id 进行响应,该 ID 用于与该列表相关的后续 API 端点:
http://my.api.com/v1.0/lists/ // POST returns some id
http://my.api.com/v1.0/lists/<id>/items // API end points include id
想象一下,客户想要对这些 API 点执行乐观更新,以增强用户体验 - 没有人喜欢看微调器。因此,当您创建列表时,您的新列表会立即出现,并带有添加项目的选项:
+-------------+----------+
| List Name | Actions |
+-------------+----------+
| My New List | Add Item |
+-------------+----------+
假设有人在初始创建调用的响应返回之前尝试添加项目。 items API 依赖于 id,因此我们知道在获得该数据之前无法调用它。但是,我们可能希望乐观地显示新项目并将对项目 API 的调用排入队列,以便在创建调用完成后触发它。
一个潜在的解决方案
我目前用来解决这个问题的方法是为每个列表提供一个操作队列 - 即将连续触发的 Redux 操作列表。
用于创建列表的 reducer 功能可能如下所示:
case ADD_LIST:
return {
id: undefined, // To be filled on server response
name: action.payload.name,
actionQueue: []
}
然后,在动作创建器中,我们将动作加入队列而不是直接触发它:
export const createListItem = (name) => {
return (dispatch) => {
dispatch(addList(name)); // Optimistic action
dispatch(enqueueListAction(name, backendCreateListAction(name));
}
}
为简洁起见,假设 backendCreateListAction 函数调用 fetch API,该 API 在成功/失败时分派消息以从列表中出列。
问题
这里让我担心的是 enqueueListAction 方法的实现。这是我访问状态以管理队列进展的地方。它看起来像这样(忽略名称上的匹配 - 这实际上使用了 clientId,但我试图保持示例简单):
const enqueueListAction = (name, asyncAction) => {
return (dispatch, getState) => {
const state = getState();
dispatch(enqueue(name, asyncAction));{
const thisList = state.lists.find((l) => {
return l.name == name;
});
// If there's nothing in the queue then process immediately
if (thisList.actionQueue.length === 0) {
asyncAction(dispatch);
}
}
}
这里,假设 enqueue 方法返回一个将异步操作插入列表 actionQueue 的普通操作。
整个事情感觉有点不合时宜,但我不确定是否还有其他方法可以解决。此外,由于我需要在我的 asyncActions 中调度,我需要将调度方法向下传递给它们。
从列表中出列的方法中有类似的代码,如果存在的话,它会触发下一个动作:
const dequeueListAction = (name) => {
return (dispatch, getState) => {
dispatch(dequeue(name));
const state = getState();
const thisList = state.lists.find((l) => {
return l.name === name;
});
// Process next action if exists.
if (thisList.actionQueue.length > 0) {
thisList.actionQueue[0].asyncAction(dispatch);
}
}
一般来说,我可以接受这一点,但我担心它是一种反模式,并且在 Redux 中可能有更简洁、惯用的方式。
感谢任何帮助。
【问题讨论】:
-
你应该看看redux-saga。
-
这是一个很好的问题,我很想看看是否有人对此有一个优雅的解决方案。我一直在使用承诺链 + mapDispatchToProps 来实现类似的目标。
-
我认为我们所有深入研究过 react/redux 的人都发现需要以任何中间件选项都不支持的方式对操作进行排队/聚合。就个人而言,我认为您最好在组件级别处理它,并在那里跟踪/比较状态,而不是在必须根据 ID 排队/出列的中间件中。
-
@Pcriulan - 如果我错了,请纠正我,但我不认为 redux-saga 解决了这个问题。从我可以从documentation 收集到的信息来看,由 saga 提取的对同一操作的非并发请求将取消待处理的请求。诚然,我还没有深入研究这些东西。
-
查看 redux-logic codewinds.com/blog/2016-08-16-business-logic-redux.html
标签: javascript reactjs redux