使用 .then 控制异步 redux 操作中的操作顺序

controlling order of operations in async redux operations with .then

我正在使用 react with 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总是颠倒的。此外,特别是在使用第二个选项时,我偶尔会遇到一个致命错误,我认为这是由其他一些顺序颠倒引起的,但我无法确切地说出是什么顺序,因为应用程序在记录之前就崩溃了。

我还尝试将调用链接起来以相互分派,但这似乎不起作用,可能是因为它们不是 returning 承诺。

这是我的 getStudents 动作创建器:

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

自从它到达服务器后它花费了一点时间是有道理的,但是如果 store.dispatch 没有 return 承诺,我怎么能.then 关闭它呢?正确的做法是什么?

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

当我 运行 进入这个问题 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')
      )
    );

我在回答我自己的问题。我问问题的方式的一个方面是误导性的。我想在我的学生之后更改视图,我很沮丧,因为我在我的日志记录中间件中看到 CHANGE_VIEW 然后 RECEIVE_STUDENTS。但这不等于说 3 和 4 颠倒了。事实上,3和4是按顺序出动的。我现在明白了,因为 getStudents() 本身是一个异步操作,dispatching 它会在异步操作完成之前解决。因此,尽管 getStudents() 和 changeView() 是按顺序发送的,但 receiveStudents() 是在 changeView() 之后发送的。在我的例子中,如果我想在 receiveStudents() 之后调度 changeView(),我需要在 getStudents() 中执行 .then dispatch(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)))
     }
   }