98

我正在开发一个待办事项应用程序。这是违规代码的一个非常简化的版本。我有一个复选框:

 <p><input type="checkbox"  name="area" checked={this.state.Pencil}   onChange={this.checkPencil}/> Writing Item </p>

这是调用复选框的函数:

checkPencil(){
   this.setState({
      pencil:!this.state.pencil,
  }); 
  this.props.updateItem(this.state);
}

updateItem 是一个映射到调度到 redux 的函数

function mapDispatchToProps(dispatch){
  return bindActionCreators({ updateItem}, dispatch);
}

我的问题是,当我调用 updateItem 操作和 console.log 状态时,它总是落后 1 步。如果复选框未选中且不为真,我仍然会将真状态传递给 updateItem 函数。我是否需要调用另一个函数来强制更新状态?

4

11 回答 11

121

您应该调用第二个函数作为 setState 的回调,因为 setState 是异步发生的。就像是:

this.setState({pencil:!this.state.pencil}, myFunction)

但是,在您的情况下,由于您希望使用参数调用该函数,因此您将不得不更具创意,并且可能创建自己的函数来调用道具中的函数:

myFunction = () => {
  this.props.updateItem(this.state)
}

将它们结合在一起,它应该可以工作。

于 2016-07-25T00:49:22.940 回答
27

由于各种原因(主要是性能),React 中的调用setState()是异步的。在幕后,React 会将多次调用批处理setState()到单个状态突变中,然后一次重新渲染组件,而不是为每个状态更改重新渲染。

幸运的是,解决方案相当简单——setState接受一个回调参数:

checkPencil: () => {
   this.setState(previousState => ({
      pencil: !previousState.pencil,
   }), () => {
      this.props.updateItem(this.state);
   });
}
于 2016-07-25T00:50:48.510 回答
13

当你使用当前状态的属性更新你的状态时,React 文档建议你使用函数调用版本setState而不是对象。

所以setState((state, props) => {...})代替setState(object).

原因是这setState更多的是要求状态改变而不是立即改变。React 将这些setState要求进行批处理以提高性能。

这意味着您正在检查的状态属性可能不稳定。这是一个需要注意的潜在陷阱。

有关更多信息,请参阅此处的文档:https ://facebook.github.io/react/docs/react-component.html#setstate


为了回答你的问题,我会这样做。

checkPencil(){
    this.setState((prevState) => {
        return {
            pencil: !prevState.pencil
        };
    }, () => {
        this.props.updateItem(this.state)
    });
}
于 2017-06-07T20:05:19.183 回答
11

在 Ben Hare 的回答中,如果有人想使用 React Hooks 实现相同的目标,我在下面添加了示例代码。

import React, { useState, useEffect } from "react"

let [myArr, setMyArr] = useState([1, 2, 3, 4]) // the state on update of which we want to call some function

const someAction = () => {
  let arr = [...myArr]
  arr.push(5) // perform State update
  setMyArr(arr) // set new state
}

useEffect(() => { // this hook will get called everytime when myArr has changed
// perform some action which will get fired everytime when myArr gets updated
   console.log('Updated State', myArr)
}, [myArr])
于 2021-05-25T03:01:54.730 回答
11

这是因为它是异步发生的,所以意味着在那段时间可能还没有更新......

根据 React v.16 文档,您需要使用setState()接受函数而不是对象的第二种形式:

状态更新可能是异步的

React 可以将多个 setState() 调用批处理到单个更新中以提高性能。

因为 this.props 和 this.state 可能是异步更新的,所以你不应该依赖它们的值来计算下一个状态。

例如,此代码可能无法更新计数器:

// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});

要修复它,请使用第二种形式的 setState(),它接受一个函数而不是一个对象。该函数将接收先前的状态作为第一个参数,并将应用更新时的道具作为第二个参数:

// Correct
this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));
于 2017-10-18T12:08:11.320 回答
7

首先设定你的价值。在继续你的作品之后。

this.setState({inputvalue: e.target.value}, function () {
    this._handleSubmit();
}); 

_handleSubmit() {
   console.log(this.state.inputvalue);
   //Do your action
}
于 2018-02-23T10:30:28.293 回答
2

尝试这个

this.setState({inputvalue: e.target.value}, function () {
    console.log(this.state.inputvalue);
    this.showInputError(inputs[0].name);
}); 

如果使用任何表单,则使用 showInputError 函数进行验证

于 2017-08-09T12:27:00.587 回答
2

我使用了 rossipedia 和 Ben Hare 的建议,并做了以下事情:

checkPencil(){
   this.setState({
      pencil:!this.state.pencil,
   }, this.updatingItem); 
}

updatingItem(){
    this.props.updateItem(this.state)
}
于 2016-07-25T01:12:41.380 回答
2

如上所述setState(),本质上是异步的。我简单地使用async await.

这是一个供参考的示例:

continue = async (e) => {
        e.preventDefault();
        const { values } = this.props;
        await this.setState({
            errors: {}
        });
        const emailValidationRegex = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i;
        if(!emailValidationRegex.test(values.email)){
            await this.setState((state) => ({
                errors: {
                    ...state.errors,
                    email: "enter a valid email"
                }
            }));
        }
   }
于 2020-05-25T15:21:45.523 回答
2

Ben 对于如何解决当前问题有一个很好的答案,但是我也建议避免重复状态

如果一个状态是 redux,你的复选框应该从 prop 或 store 中读取它自己的状态,而不是在它自己的组件和全局 store 中跟踪检查状态

做这样的事情:

<p>
    <input
        type="checkbox"
        name="area" checked={this.props.isChecked}
        onChange={this.props.onChange}
    />
    Writing Item
</p>

一般规则是,如果您发现在多个地方需要一个状态,请将其提升到一个共同的父级(并不总是 redux)以保持只有一个事实来源

于 2017-04-13T14:05:14.280 回答
0

您还可以像下面这样更新状态两次并立即更新状态,这对我有用:

this.setState(
        ({ app_id }) => ({
          app_id: 2
        }), () => {
          this.setState(({ app_id }) => ({
            app_id: 2
          }))
        } )
于 2021-05-07T12:37:12.957 回答