【问题标题】:controlling order of operations in async redux operations with .then使用 .then 控制异步 redux 操作中的操作顺序
【发布时间】:2017-11-03 03:34:22
【问题描述】:

我正在使用 react 与 redux 和 thunk 中间件。我想做一个异步请求,然后有一堆动作。然后它会以同步顺序发生。我无法实现它。

以下是我尝试过的两种方法:

addStudent(name, campusId = undefined, view = 'students') {
        const creatingStudent = axios.post('/api/student', { name: name, campusId: campusId })
            .then(res => {
                return res.data
            })
            .then(student => {
               return store.dispatch(createStudent(student))
            })
            .then(()=> {return store.dispatch(getStudents())})
            .then(()=> {return store.dispatch(changeView(view))})         
            .catch(err => console.log(err))




addStudent(name, campusId = undefined, view = 'students') {
         const creatingStudent = axios.post('/api/student', { name: name, campusId: campusId })
             .then(res => {
                 return res.data
             })
             .then(student => {
                store.dispatch(createStudent(student))
               store.dispatch(getStudents())
                store.dispatch(changeView(view))
             })       
             .catch(err => console.log(err))
     }

我想要订单: 1)axios请求 2) 派遣 createStudent 3) 派遣 getStudents 4) 调度 changeView

但是我已经安装了日志中间件,并且 3 和 4 总是颠倒的。此外,特别是使用第二个选项时,我偶尔会收到一个致命错误,我认为这是由其他一些顺序颠倒引起的,但我无法准确判断是什么顺序,因为应用程序在记录之前就崩溃了。

我也尝试链接调用以相互调度,但这似乎不起作用,可能是因为它们没有返回承诺。

这是我的 getStudents 动作创建者:

export const getStudents = () => {
   return dispatch => {
    axios.get('/api/students')
      .then(response => {
        return dispatch(receiveStudents(response.data));
      });
  }
};

这是有道理的,因为它击中服务器需要更长的时间,但是如果 store.dispatch 没有返回承诺,我怎么能 .then 关闭它?这样做的正确方法是什么?

编辑:这最初没有明确说明。我应该更明确地说,我的挫败感是 changeViews() 是在 receiveStudents() 之前发送的,而不是像我暗示的那样,changeViews() 是在 getStudents() 之前发送的。我不知道 getStudents() 何时发送。

【问题讨论】:

    标签: reactjs redux axios redux-thunk


    【解决方案1】:

    当我遇到这个问题https://github.com/reactjs/redux/issues/723 时,这次谈话对我帮助很大。

    你应该可以用 axios 做这样的事情:

    axios.all([
      store.dispatch(createStudent(student)),
      store.dispatch(getStudents()),
      store.dispatch(changeView(view))
    ]).then(() => {
      console.log('I did everything!');
    });
    

    您可以在每次分派后使用 .then 来链接操作。我看到你说你试过了,但是这个设置是直接从 redux-thunk 中间件 github 自述文件中提取的,应该适用于你的情况https://github.com/gaearon/redux-thunk

    return dispatch(
          makeASandwichWithSecretSauce('My Grandma')
        ).then(() =>
          Promise.all([
            dispatch(makeASandwichWithSecretSauce('Me')),
            dispatch(makeASandwichWithSecretSauce('My wife'))
          ])
        ).then(() =>
          dispatch(makeASandwichWithSecretSauce('Our kids'))
        ).then(() => //Chain another dispatch
          dispatch(getState().myMoney > 42 ?
            withdrawMoney(42) :
            apologize('Me', 'The Sandwich Shop')
          )
        );
    

    【讨论】:

    • 嘿,感谢您的帮助,但我不知道这个想法是否达到了我想要的效果——我可能不太清楚。我不希望 store.dispatch(getStudents()) 在 createStudent 完成之前执行,并且我不希望 changeView 在 getStudents 完成之前执行。据我了解 .all 命令,它会在所有承诺都得到解决后解决。我仍在阅读您发送的页面,并试图弄清楚讨论的部分内容是否与我的案例相关。
    • 好的,更新答案以显示如何一个接一个地调度操作
    • 起初我很难看到这与我的第一个示例之间的区别,但现在我看到了一个:文档中的原始函数将 dispatch 作为参数并使用 dispatch 而不是 store.dispatch 来将操作发送到商店。也许这就是我的问题。也许我应该在别处定义一个异步操作创建器并使用 addStudent 来调用它。我会尝试并报告。
    • 好的,我回来汇报。我进行了重构,以便我的 addStudents 现在在一个函数上调用 store.dispatch,该函数是一个异步操作创建者,该函数将 dispatch 作为参数并通过 dispatch 而不是 store.dispatch 调度 getStudents、changeView 等。 changeView 仍然在 getStudents 之前执行。在这个例子中,就好像在为孩子们做三明治之前,withdrawMoney 正在执行。我需要制作一个我知道的最低限度的可重现示例——它只是感觉数据库等等让人不知所措,但如果你或其他任何人仍然参与其中,我会这样做。
    • 我想我现在明白了;也许我应该更明确地说明 what 发生了乱序。我的意图是等到我有了学生,然后改变看法。当我看到 changeView() 被调度,然后 receiveStudents() 被调度时,我很沮丧,而且我在我的学生之前改变了我的观点。但我想我现在看到可以解决 getStudents() 的调度,并且 .then 链可以在 axios 请求完成和 receiveStudents之前继续调度 changeView() > 被调度,更新状态。
    【解决方案2】:

    我正在回答我自己的问题。我问这个问题的方式的一个方面是误导。在我有了学生之后,我想更改视图,但我很沮丧,因为我在日志中间件中看到了 CHANGE_VIEW,然后是 RECEIVE_STUDENTS。但这与说 3 和 4 颠倒是不一样的。事实上,3和4是按顺序发出的。我现在明白,因为 getStudents() 本身就是一个异步操作,dispatching 它会在异步操作完成之前解决。因此,即使 getStudents() 和 changeView() 是按顺序分派的,receiveStudents() 也是在 changeView() 之后分派的。就我而言,如果我想在receiveStudents() 之后调度changeView(),我需要在getStudents() 中调度(changeView())。

    这是完成我想要的重构代码:

    addStudent(student, view = 'students') {
        const creatingStudent = axios.post('/api/student', student)
            .then(res => res.data)
            .then(student => store.dispatch(createStudent(student)))
            .then(()=> store.dispatch(getStudents(view)))      
            .catch(err => console.log(err))
    }
    
    
    
    const getStudents = (view) => {
       return dispatch => {
         axios.get('/api/students')
           .then(res => dispatch(receiveStudents(res.data)))
           .then(()=>dispatch(changeView(view)))
         }
       }
    

    【讨论】:

      猜你喜欢
      • 2018-04-28
      • 2016-06-02
      • 1970-01-01
      • 2020-04-23
      • 1970-01-01
      • 2018-01-31
      • 2018-11-26
      • 2016-12-20
      • 2017-09-26
      相关资源
      最近更新 更多