ReactJS 状态未更新在 setState 回调中

Posted

技术标签:

【中文标题】ReactJS 状态未更新在 setState 回调中【英文标题】:ReactJS state not updated In setState callback 【发布时间】:2017-07-23 00:52:33 【问题描述】:

我目前正在构建一个 SIP 电话,当前呼叫由 SipPhone 类处理,并使用 React 显示在前端。 SipPhone 有一个调用列表,这些调用会触发 React 组件正在监听的回调。

主电话组件的初始状态包含一个空的Immutable List:

constructor(props) 
    super(props);
    ...
    this.state = 
        calls: List(),
    ;

每当 SipPhone 更新时,此 calls 列表会通过回调触发的事件进行更新。

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 已经有一段时间了,从来没有遇到过这个问题……有什么想法吗?

【问题讨论】:

您能否发布完整的代码示例,例如调用第二个代码块的位置? 我添加了更多细节——不幸的是,在这种情况下很难给出完整的代码示例,因为它是一个相当大的项目。 算了,我一时误会了。 @RyanMcClure 嗨..我根据您的示例创建了一个fiddle,它运行良好。唯一显着的区别是我使用了handleUpdate(calls) 而不是handleUpdate = ( calls )。你能看看吗?参数中是否需要那些完美的大括号?? @RyanMcClure 解决了您的问题吗? 【参考方案1】:

事实证明,在某些情况下,我的代码中的另一个函数在调用 componentWillUpdate 之前设置了状态,导致它忽略了对 setState 的初始调用。这是错误的根源。

【讨论】:

【参考方案2】:

我个人发现 JsSIP 库非常复杂,因为方法和嵌套回调太多。这与您通常在 React 应用程序中使用的非常不同。我和我的朋友曾经创建了一个名为<SipProvider/> 的简单组件,它将所有 JsSIP 复杂性抽象出来,让我们通过配置 props 和使用上下文方法来进行调用。我们终于在 npm 上发布了这个包 - 也可以随时从中受益!https://www.npmjs.com/package/react-sip

如果您想在应用程序的状态中存储一些数据,但又不想打扰 redux / mobx / apollo 客户端,那么一个名为 recompose 的库可能会有所帮助。它使您可以将状态提升为更高阶的组件,从而将状态逻辑与其表示分离。我在几个项目中一直在使用withState() / withReducer(),我很难想象再次使用this.setState()

【讨论】:

【参考方案3】:

我们之前遇到过这个问题,当我们使用 Immutable(而不是普通的 JS)时

四处挖掘,在 react docs 中发现了这个文档 sn-p

setState() 不会立即改变 this.state 而是创建一个挂起的状态转换。调用此方法后访问 this.state 可能会返回现有值。

不保证 setState 调用的同步操作,并且调用可能会被批处理以提高性能。

除非真的强制使用setState 的回调函数,否则我建议使用componentDidUpdate

【讨论】:

所以据我了解,新状态应该始终反映在回调中,因为它是在完成后调用的。但是在我的情况下,新状态实际上根本没有更新。在渲染函数中记录列表会显示未更改的列表。

以上是关于ReactJS 状态未更新在 setState 回调中的主要内容,如果未能解决你的问题,请参考以下文章

ReactJS TypeError:无法读取未定义的属性“setState”[重复]

ReactJS:警告:setState(...):在现有状态转换期间无法更新

ReactJs:获取无法读取未定义错误的属性“setState”[重复]

ReactJS:setState值不更新[重复]

React JS:setState中的previousState在状态更新后不保留先前状态的数据

React JS:调用 setState 后组件未更新