使用 .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)))
}
}
我正在使用 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)))
}
}