React setState not Updating Immediately

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

 <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步。如果复选框未选中且不为 true,那么仍然可以得到传递给 updateItem 函数的 true 状态。我是否需要调用另一个函数来强制状态更新?

154631 次浏览

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

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

然而,在你的情况下,既然你想用一个参数来调用这个函数,那么你就必须更有创造性一些,也许你可以创建一个自己的函数来调用道具中的函数:

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

把它们结合在一起,应该会奏效。

由于各种原因(主要是性能) ,在 React 中调用 setState()是异步的。在封面下,React 将把对 setState()的多个调用批处理为单个状态变异,然后一次性重新呈现组件,而不是每次状态变化都重新呈现组件。

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

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

我采用了 Rossipedia 和 Ben Hare 的建议,并且做了以下事情:

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


updatingItem(){
this.props.updateItem(this.state)
}

本有一个伟大的答案,如何解决迫在眉睫的问题,但我也建议避免重复的国家

如果一个状态处于还原状态,那么您的复选框应该从道具或存储中读取它自己的状态,而不是跟踪它自己的组件和全局存储中的复选状态

做这样的事情:

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

一般的规则是,如果您发现一个状态在多个地方都需要,那么将其提升到一个共同的父级(并不总是还原) ,以保持只有一个真理来源

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

所以是 setState((state, props) => {...})而不是 setState(object)

原因在于,setState更多的是对状态变更的请求,而不是立即变更。对那些 setState调用进行批处理以提高性能。

也就是说你要检查的国家财产可能不稳定。 这是一个需要注意的潜在陷阱。

有关详细信息,请参阅文档: https://facebook.github.io/react/docs/react-component.html#setstate


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

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

试试这个

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

如果使用任何表单,则用于验证的 showInputError 函数

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

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

State Updates May Be Asynchronous

React 可以将多个 setState ()调用批处理为一个更新 表演。

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

For example, this code may fail to update the counter:

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

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

// Correct
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}));

首先设定你的价值,然后进行你的工作。

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


_handleSubmit() {
console.log(this.state.inputvalue);
//Do your action
}

如上所述,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"
}
}));
}
}

你也可以像下面这样更新状态两次,然后立即进行状态更新,这对我很有用:

this.setState(
({ app_id }) => ({
app_id: 2
}), () => {
this.setState(({ app_id }) => ({
app_id: 2
}))
} )

对于 Ben Hare 的回答,如果有人想要使用 React Hook 达到同样的效果,我在下面添加了示例代码。

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])

以下是基于 React Hooks 的解决方案。

由于 React useState是异步更新状态的,所以如果需要查看这些更改,请在 useEffect挂钩中检查它们。

确保每次使用变量时都在 useState 中给出 initialState。比如第一行和第二行。如果我没有给任何在它将工作双击,以填补错误变量。

  1) let errorsArray = [];
2) let [errors, setErrors] = useState(errorsArray);
3) let [firstName, setFirstName] = useState('');
4) let [lastName, setLastName] = useState('');
let [gender, setGender] = useState('');
let [email, setEmail] = useState('');
let [password, setPassword] = useState('');


const performRegister = () => {
console.log('firstName', isEmpty(firstName));
if (isEmpty(firstName)) {
console.log('first if statement');
errorsArray.push({firstName: 'First Name Cannot be empty'});
}
if (isEmpty(lastName)) {
errorsArray.push({lastName: 'Last Name Cannot be empty'});
}
if (isEmpty(gender)) {
errorsArray.push({gender: 'Gender Cannot be empty'});
}
if (isEmpty(email)) {
errorsArray.push({email: 'Email Cannot be empty'});
}
if (isEmpty(password)) {
errorsArray.push({password: 'Password Cannot be empty'});
}
console.log('outside ERRORS array :::', errorsArray);
setErrors(errorsArray);
console.log('outside ERRORS :::', errors);
if (errors.length > 0) {
console.log('ERROR exists');
}
};