在 redux 中在哪里调度多个操作?
Posted
技术标签:
【中文标题】在 redux 中在哪里调度多个操作?【英文标题】:Where to dispatch multiple actions in redux? 【发布时间】:2017-11-03 10:29:15 【问题描述】:我将 redux 与 connect
和 redux-thunk
中间件和容器一起使用。
当前当用户执行一个动作时,例如单击一个按钮,我需要调度该动作(同步),这将调度其他几个动作(异步)。
我知道从 reducer 中调度操作是一种反模式。
我想知道这个代码的合适位置。
目前我不确定它是否应该留在:
动作创建者。 在容器中使用 store.subscribe。【问题讨论】:
我相信this 描述了您正在寻找的确切模式。只需阅读该页面,您最感兴趣的部分可能是他们描述fetchPosts
函数的地方。
@saadq 感谢您的链接,它看起来像在动作创建者中......正确吗?
请记住,dispatch
是 SYNCHRONOUS 操作 :)
【参考方案1】:
documentation 推荐的方法是在动作创建器中,如下所示:
function actionCreator(payload)
return dispatch =>
dispatch(action1(payload))
dispatch(action2(payload))
然后您可能希望将动作创建者作为道具附加并使用mapDispatchToProps
将其传递给容器,就像在提到的示例here 中一样。所以它看起来像这样:
const mapDispatchToProps = dispatch => (
action1: some_payload => dispatch(action1(some_payload))
action2: some_payload => dispatch(action2(some_payload))
)
// your component
export default connect(mapStateToProps, mapDispatchToProps)(YourApp)
【讨论】:
不幸的是,第一个链接已损坏。它应该指向github.com/reactjs/redux/blob/master/docs/advanced/… 吗? 考虑在此处添加代码,而不仅仅是链接文档 为多个调度编写单元测试的最佳方式是什么? @Shiraz 文档中有一个示例:redux.js.org/recipes/writing-tests#async-action-creators @Mμ。通过向您的示例 actionCreator 提供 Promise.Resolve() 响应,就可以使用redux.js.org/recipes/writing-tests#async-action-creators 中显示的模式对其进行测试。我现在已经用建议的代码提供了对 OP 问题的答案 - 也许我还应该添加一些单元测试代码?!【参考方案2】:正如其他人指出的那样,The action creator
是调度多个操作的正确位置。
下面是action1
如何在您的action creator
中调度其他操作的示例。
const action1 = id =>
return dispatch =>
dispatch(action2(id))
dispatch(action3(id))
【讨论】:
【参考方案3】:虽然@GibboK 的解决方案对我不起作用:
const mapDispatchToProps = (dispatch) => (
action2: id => dispatch(Actions.action2(id)),
action3: id => dispatch(Actions.action3(id)),
action1: (dateId, attrId) =>
return dispatch =>
dispatch(Actions.action2(dateId));
dispatch(Actions.action3(attrId));
);
我最终选择了redux-batched-actions。像魅力一样工作:
const mapDispatchToProps = (dispatch) => (
action2: id => dispatch(Actions.action2(id)),
action3: id => dispatch(Actions.action3(id)),
action1: (dateId, attrId) =>
dispatch(batchActions([
Actions.action2(dateId),
Actions.action3(attrId)
]))
);
【讨论】:
【参考方案4】:动作创建者是调度多个动作的正确位置。虽然像下面这样的代码可以工作:
function actionCreator(payload)
return dispatch =>
dispatch(action1(payload))
dispatch(action2(payload))
我强烈建议基于 redux-thunk
的动作创建者始终返回已解决的 Promise,以便此类动作创建者可以成为另一个异步调用的一部分。因此,对上述内容的最简单更新是:
function actionCreator(payload)
return dispatch =>
dispatch(action1(payload));
dispatch(action2(payload));
return Promise.resolve();
然后可以通过以下方式发送到上述内容:
actionCreator(payload).then(doAnotherAction(anotherPayload))
或以下,如果我们需要维护调用顺序:
actionCreator(payload).then(() => doAnotherAction(anotherPayload))
如果您希望“面向未来”您的动作创建者,以便它可以处理调用异步和同步动作创建者,您可以将其编写为:
function actionCreator(payload)
return dispatch =>
Promise.resolve(dispatch(action1(payload))).then(
() => dispatch(action2(payload)));
而且,如果你喜欢 ES6 箭头符号,上面可以定义为:
const actionCreator = payload => dispatch =>
Promise.resolve(dispatch(action1(payload))).then(
() => dispatch(action2(payload)));
【讨论】:
感谢您的回答。我真的在寻找一种按顺序进行多次调度的方法。【参考方案5】:如果您有Promise Middleware,则可以使用此语法,以便在您的dispatch(topLevelAction())
上使用.then()
:
export const topLevelAction = () => dispatch =>
return Promise.all([dispatch(action1()), dispatch(action2()), dispatch(action3())])
【讨论】:
【参考方案6】:最简单的方法是使用专门的中间件redux-soldier:
import createStore, applyMiddleware from 'redux'
import reduxSoldierMiddleware from 'redux-soldier'
const store = createStore(rootReducer, applyMiddleware(reduxSoldierMiddleware))
store.dispatch([
type: 'INCREMENT', // traditional action
addTodo('Start using redux-soldier'), // action creator
fetchUser(), // thunk action
])
redux-soldier
也是redux-thunk
的完全替代品
有关更多信息,请查看文档redux-soldier。
【讨论】:
【参考方案7】:对于 2020 年的男士们... 动作应该在动作创建者中进行。对于那些想要调度一个动作并从 API 获取/发布一些数据的人可以使用这个想法。
假设我们有一个actions.js
文件,并且我们希望在获取数据之前调度加载操作。
function requestPosts()
return
type: "loading"
这是抓取动作函数
function fetchPosts()
return dispatch =>
// dispatch the loading
dispatch(requestPosts());
// fetch data from api
return fetch("https://www.yoururl.com/api")
.then(response => response.json())
.then(json => dispatch(
type: "fetching successful",
payload: json
));
【讨论】:
【参考方案8】:"had similar issue. had to create a function
that accepts object with the actions you want to
dispatch to the store and individual params for
respective action"
dispatchMultiple(params:
params1: "<arg for first action>" ,
params2: "<arg for second action>",
,
)
const dispatchMultiple = (obj) =>
dispatch(obj.actions.action1(obj.params.params1));
dispatch(obj.actions.action2(obj.params.params2));
;
【讨论】:
【参考方案9】:我不知道确切的用例,但由于 redux 使用异步逻辑,任何在事件循环的下一个滴答中运行第二次调度的解决方案都应该有效。
store.dispatch( type: 'ADD_TODO', text: 'Buy milk.' );
setTimeout(() =>
store.dispatch( type: 'ADD_TODO', text: 'Take out garbage.' );
, 0);
Promise.resolve(() =>
store.dispatch( type: 'ADD_TODO', text: 'Water plants.' );
);
如果第二个 dispatch 依赖于第一个 dispatch 的 actions,你可以从 store 中获取 state,检查它是否满足条件,然后 dispatch 第二个 action。最好保持操作的逻辑清晰和细化。
因此,要回答这个问题,调度多个操作的正确位置是在第一个操作发起的点击处理程序内。
【讨论】:
以上是关于在 redux 中在哪里调度多个操作?的主要内容,如果未能解决你的问题,请参考以下文章
在 React Redux 中调度操作之前等待多个 Axios 调用
使用 Jest 在 React Redux 中对多个调度的操作进行单元测试