ChatGPT解决这个技术问题 Extra ChatGPT

为什么调用 react setState 方法不会立即改变状态?

我正在阅读 文档的 Forms 部分,并尝试使用此代码来演示 onChange 的用法 (JSBIN)。

var React= require('react');

var ControlledForm= React.createClass({
    getInitialState: function() {
        return {
            value: "initial value"
        };
    },

    handleChange: function(event) {
        console.log(this.state.value);
        this.setState({value: event.target.value});
        console.log(this.state.value);

    },

    render: function() {
        return (
            <input type="text" value={this.state.value} onChange={this.handleChange}/>
        );
    }
});

React.render(
    <ControlledForm/>,
  document.getElementById('mount')
);

当我在浏览器中更新 <input/> 值时,handleChange 回调中的第二个 console.log 打印与第一个 console.log 相同的 value,为什么我在handleChange 回调的范围?

如果您使用挂钩,请查看 useState set method not reflecting change immediately
React 18 引入了 automatic batching

M
Michael Parker

来自 React 的 documentation

setState() 不会立即改变 this.state 而是创建一个挂起的状态转换。在调用此方法后访问 this.state 可能会返回现有值。无法保证对 setState 的调用同步操作,并且可能会批处理调用以提高性能。

如果您希望在状态更改发生后执行函数,请将其作为回调传递。

this.setState({value: event.target.value}, function () {
    console.log(this.state.value);
});

好答案。我需要做的观察是小心使用 valueLink。如果您不必格式化/屏蔽输入,它会很好。
您可能还想查看 componentDidUpdate。状态改变后会被调用。
快速提问,如果我可以的话,我看到一旦我们将我们需要的函数作为回调传递给 setState ,我希望在调用 render() 之前先执行 func。但我看到顺序是 setState() -> render() -> setStates' callback() 。这是正常的吗?如果我们想根据我们在回调中所做的事情来控制我们的渲染怎么办?应该组件更新吗?
更改组件的状态将始终触发重新渲染,除非 shouldComponentUpdate 中另有指定行为。在您传递给 setState 的回调中,您到底想要在重新渲染之前发生什么?
...为什么?有人可以证明这一点吗?
Y
Yo Wakita

如 React 文档中所述,不能保证 setState 被同步触发,因此您的 console.log 可能会在更新之前返回状态。

Michael Parker 提到在 setState 中传递回调。状态更改后处理逻辑的另一种方法是通过 componentDidUpdate 生命周期方法,这是 React 文档中推荐的方法。

通常我们建议使用 componentDidUpdate() 来代替这种逻辑。

当可能有连续的 setState 被触发并且您希望在每次状态更改后触发相同的函数时,这尤其有用。您可以将函数放在 componentDidUpdate 内,而不是向每个 setState 添加回调,必要时在其中包含特定逻辑。

// example
componentDidUpdate(prevProps, prevState) {
  if (this.state.value > prevState.value) {
    this.foo();  
  }
}

k
kurokiiru

你可以尝试使用 ES7 async/await。例如使用您的示例:

handleChange: async function(event) {
    console.log(this.state.value);
    await this.setState({value: event.target.value});
    console.log(this.state.value);
}

您的答案与其他高质量答案有何不同?
另一个答案是关于在 setState() 中使用回调。我想我把它放在这里是为了那些不适用回调用例的人。例如,当我自己遇到这个问题时,我的用例在设置后立即涉及更新状态的开关案例。因此,使用 async/await 优于使用回调。
如果我总是在想要更新某些状态然后等待它更新时总是使用 await ,这会影响性能吗?如果我将多个等待 setStates 放在一个链下,它会在每次 setState 更新后呈现吗?还是在最后一次 setState 更新之后?
y
yangsibai

注意 react 生命周期方法!

http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/

https://reactjs.org/docs/react-component.html

我工作了几个小时才发现在每个 setState() 之后都会调用 getDerivedStateFromProps

😂


R
Ritwik

async-await 语法非常适用于以下内容...

changeStateFunction = () => {
  // Some Worker..

  this.setState((prevState) => ({
  year: funcHandleYear(),
  month: funcHandleMonth()
}));

goNextMonth = async () => {
  await this.changeStateFunction();
  const history = createBrowserHistory();
  history.push(`/calendar?year=${this.state.year}&month=${this.state.month}`);
}

goPrevMonth = async () => {
  await this.changeStateFunction();
  const history = createBrowserHistory();
  history.push(`/calendar?year=${this.state.year}&month=${this.state.month}`);
}

D
Dean P

由于 setState 的异步特性,在调用 setState 方法后访问 this.state 不能保证返回更新的状态。

为保证调用 setState 后更新,您可以采用两种解决方案。

解决方案 1: 作为上述答案之一中的 mentioned,将您的代码放入 componentDidUpdate 方法中

解决方案 2: 如上述答案的 another 中所述,将您的内容作为回调传递

 this.setState({value: myValue}, function () {
    this.functionThatIsExecutedWhenStateIsUpdated();
});

需要注意的是,这两种解决方案显然不能互换。一个不能轻易解决另一个的所有用例。作为一般规则,如果可以,最佳实践表明解决方案 1 是首选。但是,在某些用例中,只有解决方案 2“更有效”有效,例如“update-my-view-and-post-my-data”用例。这个用例是这样的:

https://i.stack.imgur.com/hktFa.png

如果你不做任何一个解决方案,即如果你只在你的代码中这样说:

addToItemArray = () => { 
     this.setState{{ scheduledItemsArray: newObjectListWithMax}}   
     this.postData();
}

<button className="btn btn-secondary btn-block" onClick={this.addToItemArray}>Add Shedule</button>

...您将发布列表排除“Delivery to Max”项目,因为当您this.postData()时状态不会更新(再次,因为它是异步的)。

如果您使用解决方案 1,您将在 Schedule Name 文本框中输入每个字符后进行 POST!

还有其他方法可以满足此用例,但解决方案 2 在阅读代码时最能传达意图。

鉴于此用例在几乎每个 Web 应用程序中无处不在,Michael's answer 所解释的回调技术是每个开发人员工具包中不可或缺的一段代码。


S
S.Yadav

有时状态会出现此问题。
如果是钩子,您应该使用 useEffect 钩子,如下所示 -

const [fruit, setFruit] = useState('');
 
setFruit('Apple');
useEffect(() => {
  console.log('Fruit', fruit);
}, [fruit])

这拯救了我的一天,希望能帮助你!!!


V
Vishal Bisht

简单地说 - this.setState({data: value}) 本质上是异步的,这意味着它会移出调用堆栈,除非解决,否则只会返回调用堆栈。

请阅读有关事件循环以清楚了解 JS 中的异步性质以及为什么需要时间来更新 -

https://medium.com/front-end-weekly/javascript-event-loop-explained-4cd26af121d4

因此 -

    this.setState({data:value});
    console.log(this.state.data); // will give undefined or unupdated value

因为更新需要时间。实现上述过程——

    this.setState({data:value},function () {
     console.log(this.state.data);
    });

Y
Yilmaz

React 处理不同的设置状态调用,以便它可以确定重新呈现网站的最佳策略是什么。

想象一下,您有一个应用程序,其中包含许多不同的组件。也许,只需单击一个按钮,您就可以更新多个组件的状态,而不仅仅是当前组件。在这种情况下,React 不希望完全隔离并独立完成所有这些不同的更新。

React 想弄清楚它是否可以将所有这些更新堆叠在一起,也许有一种更优化的方式来更新这些组件,从而提高性能。这就是 React 在幕后所做的。因此,设置状态调用是异步调用。