我在以前的ReactJS项目中使用过以下模式-很多!
componentDidMount() {
var promises = [];
var promise1 = this.AsyncFunc1().then(res => {
this.setState({some_state1: res.data.results});
}).catch(error => {
//deal with error
});
var promise2 = this.AsyncFunc2().then(res => {
this.setState({some_state2: res.data.results});
}).catch(error => {
//deal with error
});
promises.push(promise1);
promises.push(promise2);
Promise.all(promises).then(() => {
// Use the state variables
}).catch(error => {
// deal with error
});
}
我知道状态是异步设置的,不能立即使用-我避免在异步函数的then语句中设置状态后立即访问该状态-但我在以前的项目中一直访问promise解析部分中的状态变量值-但在我正在处理的这个新项目中,它时断时续地失败,因为状态变量值不一致。我已经将临时变量设置为res.data.results值,并在Promise.all部分中使用这些值。我以前的项目已经生产了两年多,没有出现任何问题(我知道(——我需要回去重新编写代码吗?我是否错误地假设状态变量值将在Promise.all部分中可用?我很感激你的帮助!
是的,您做了一个错误的假设;你的承诺可能会在州政府可用之前兑现。来自setState
文档,重点挖掘:
setState()
将更改排入组件状态队列,并告诉React此组件及其子级需要使用更新后的状态重新提交。这是用于更新用户界面以响应事件处理程序和服务器响应的主要方法。
setState()
并不总是立即更新组件。它可能会批处理或推迟更新。这使得在调用setState()
之后立即读取This.state成为一个潜在的陷阱请使用componentDidUpdate
或setState
回调(setState(updater, callback)
(,这两种回调都保证在应用更新后激发。如果需要根据以前的状态设置状态,请阅读下面的updater
参数。
还有一个关于你的案例的常见问题条目,再次强调我的:
为什么setState给了我错误的值
在React中,
this.props
和this.state
都表示渲染值,即当前屏幕上的内容。对
setState
的调用是异步的-不依赖于此。状态在调用setState
后立即反映新值。如果需要根据当前状态计算值,请传递updater函数而不是对象(有关详细信息,请参见下文(。
在第二个引号中,状态变量直到渲染完成后才会更新,即使您在调用setState
后没有立即读取state
,但您的Promise.all
仍有可能在this.state
更新之前激发,React绝对保留这样做的权利。审核您以前使用此模式可能是个好主意。
如果你真的想先渲染,可以选择一些选项:
- 使用
componentDidUpdate
并检查是否设置了两个状态变量,常见问题解答建议这样做 - 使用第二个
setState
参数updater
,它将在setState
生效后回电。与componentDidUpdate
相比,不建议这样做 - 使用挂钩时,请使用
useEffect
。您可以将第二个参数中的some_state1
和some_state2
传递给useEffect
,以便仅在值更改时生效 - 在AsyncFunc
then
处理程序中,将代码包装在flushSync
中。文档强烈建议不要使用此选项:flushSync
不像上面的其他选项那样具体,但对于旧代码的权宜之计,它可能对您有效
如果在Promise.all()
处理程序运行之前不需要更新UI,可以将解析的值保存到本地变量,也可以确保return
是AsyncFuncthen
处理程序中的值。如果您的// deal with error
处理程序提供回退值,那么您也可以从那里的catch
处理程序返回这些值;相反,如果您不希望Promise.all()
处理程序在这两个调用中的任何一个失败时运行,则应确保它们从catch
块中重新调用throw
异常,这样您保存的承诺将被拒绝。
(当然,您也可以将两个setState
调用移动到Promise.all
处理程序,这样在两个值都存在之前,您甚至不需要尝试调用setState
,但我认为您需要来自每个AsyncFunc的部分UI更新。(