我目前遇到了一种情况,我需要连续运行 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 点执行乐观更新,以增强 UX - 没有人喜欢看微调器。因此,当您创建列表时,您的新列表会立即出现,并带有添加项目的选项:
+-------------+----------+
| 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 函数调用获取 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 中可能有一种更简洁、更惯用的方式来做到这一点。
任何帮助表示赞赏。