ReactJS 状态未更新在 setState 回调中
ReactJS state not updated In setState callback
我目前正在构建一个 SIP phone,其中当前呼叫由 SipPhone class 处理,并使用 React 在前端显示。 SipPhone 有一个调用列表,可以触发 React 组件正在监听的回调。
主要 phone 组件的初始状态包含空 Immutable List:
constructor(props) {
super(props);
...
this.state = {
calls: List(),
};
}
此 calls
列表通过 SipPhone 更新时回调触发的事件进行更新。
handleUpdate = ({ calls }) => {
const nextCalls = List(calls.map(call => {
return new Call({ ... }) // Call is an Immutable Record
});
console.log(nextCalls.toJS()); // This prints the new list I want to save
this.setState({ calls: nextCalls }, () => {
console.log(this.state.calls.toJS()); // The list is empty here
});
}
有时它会成功更新 calls
列表,而在其他时候 calls
不会更改。当我在设置状态之前记录列表时,它应该是这样,但是当登录 setState 回调时,它与之前的状态保持不变。有时有效,有时无效。
为了进一步测试这一点,我添加了一个状态变量 tick
,每次我在此处设置状态时该变量都会递增。此更改准确反映在回调中,而调用列表保持不变。
我似乎想不出它这样做的任何原因。实际上,我使用普通数组而不是不可变列表开始这个项目,并遇到了同样的问题。我已经使用 React 一段时间了,但从未 运行 解决过这个问题……有什么想法吗?
我们以前遇到过这个问题,当时我们使用 Immutable(而不是普通的 JS)
四处挖掘,在 React 文档中发现了这个文档片段
setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value.
There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains.
除非真的强制使用 setState
的回调函数,否则我建议使用 componentDidUpdate
。
事实证明,我的代码中的另一个函数在某些情况下会在调用 componentWillUpdate 之前设置状态,导致它忽略对 setState 的初始调用。这是错误的来源。
我个人觉得 JsSIP 库非常复杂,因为太多的方法和嵌套的回调。这与您通常在 React 应用程序中使用的内容非常不同。我和我的朋友曾经创建了一个名为 <SipProvider/>
的简单组件,它抽象了所有 JsSIP 的复杂性,让我们仅通过配置道具和使用上下文方法来进行调用。我们终于在 npm 上发布了那个包——也可以从中受益!
https://www.npmjs.com/package/react-sip
如果你想在应用程序的状态中存储一些数据,但不想为 redux / mobx / apollo 客户端而烦恼,在一些项目中有一个名为 recompose
may be helpful. It lets you lift the state into a higher-order component and thus separate the state logic from its representation. I've been using withState()
/ withReducer()
的库,我很难想象再次使用 this.setState()
!
我目前正在构建一个 SIP phone,其中当前呼叫由 SipPhone class 处理,并使用 React 在前端显示。 SipPhone 有一个调用列表,可以触发 React 组件正在监听的回调。
主要 phone 组件的初始状态包含空 Immutable List:
constructor(props) {
super(props);
...
this.state = {
calls: List(),
};
}
此 calls
列表通过 SipPhone 更新时回调触发的事件进行更新。
handleUpdate = ({ calls }) => {
const nextCalls = List(calls.map(call => {
return new Call({ ... }) // Call is an Immutable Record
});
console.log(nextCalls.toJS()); // This prints the new list I want to save
this.setState({ calls: nextCalls }, () => {
console.log(this.state.calls.toJS()); // The list is empty here
});
}
有时它会成功更新 calls
列表,而在其他时候 calls
不会更改。当我在设置状态之前记录列表时,它应该是这样,但是当登录 setState 回调时,它与之前的状态保持不变。有时有效,有时无效。
为了进一步测试这一点,我添加了一个状态变量 tick
,每次我在此处设置状态时该变量都会递增。此更改准确反映在回调中,而调用列表保持不变。
我似乎想不出它这样做的任何原因。实际上,我使用普通数组而不是不可变列表开始这个项目,并遇到了同样的问题。我已经使用 React 一段时间了,但从未 运行 解决过这个问题……有什么想法吗?
我们以前遇到过这个问题,当时我们使用 Immutable(而不是普通的 JS)
四处挖掘,在 React 文档中发现了这个文档片段
setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value.
There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains.
除非真的强制使用 setState
的回调函数,否则我建议使用 componentDidUpdate
。
事实证明,我的代码中的另一个函数在某些情况下会在调用 componentWillUpdate 之前设置状态,导致它忽略对 setState 的初始调用。这是错误的来源。
我个人觉得 JsSIP 库非常复杂,因为太多的方法和嵌套的回调。这与您通常在 React 应用程序中使用的内容非常不同。我和我的朋友曾经创建了一个名为 <SipProvider/>
的简单组件,它抽象了所有 JsSIP 的复杂性,让我们仅通过配置道具和使用上下文方法来进行调用。我们终于在 npm 上发布了那个包——也可以从中受益!
https://www.npmjs.com/package/react-sip
如果你想在应用程序的状态中存储一些数据,但不想为 redux / mobx / apollo 客户端而烦恼,在一些项目中有一个名为 recompose
may be helpful. It lets you lift the state into a higher-order component and thus separate the state logic from its representation. I've been using withState()
/ withReducer()
的库,我很难想象再次使用 this.setState()
!