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

lnlaulya  于 2023-02-28  发布在  Java
关注(0)|答案(9)|浏览(202)

我正在阅读reactjs文档的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打印的value与第一个console.log打印的value相同,为什么在handleChange回调函数的作用域中看不到this.setState({value: event.target.value})的结果?

c6ubokkw

c6ubokkw1#

来自React的文档:
setState()不会立即改变this.state,但会创建挂起的状态转换。调用此方法后访问this.state可能会返回现有值。无法保证对setState的调用的同步操作,并且可能会对调用进行批处理以提高性能。
如果希望函数在状态更改后执行,请将其作为回调传入。

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

alen0pnh2#

正如React文档中提到的,不能保证setState被同步触发,因此您的console.log可能返回更新之前的状态。
Michael帕克提到在setState中传递回调函数,另一种处理状态改变后的逻辑的方法是通过componentDidUpdate生命周期方法,这是React文档中推荐的方法。
一般来说,我们建议使用componentDidUpdate()来处理此类逻辑。
当可能有连续的setState被触发,并且您希望在每次状态更改后触发相同的函数时,这一点特别有用。您可以将函数放置在componentDidUpdate中,如果需要,可以在其中使用特定的逻辑,而不是为每个setState添加回调。

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

busg9geu3#

您可以尝试使用ES 7 async/await。例如,使用您的示例:

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

olhwl3o24#

注意React生命周期方法!

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

bbmckpt7

bbmckpt75#

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

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

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

pod7payv

pod7payv6#

由于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”用例。此用例如下所示:
在添加一个项目之后,比如说,“AddSchedule”,我想both将该项目添加到前端列表,并立即将刚刚更新的列表发布到后端,如下面的概念所示:

如果您不执行任何一种解决方案,即,如果您只在代码中这样说:

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所解释的回调技术是每个开发人员工具包中不可或缺的代码。

dkqlctbz

dkqlctbz7#

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}`);
}
f4t66c6m

f4t66c6m8#

React baths调用不同的set state,这样它就可以确定重新呈现网站的最佳策略是什么。
想象一下,你有一个应用程序,其中有很多不同的组件。也许,通过单击一个按钮,你可以更新多个组件的状态,而不仅仅是当前组件的状态。在这种情况下,React不想完全隔离并独立地执行所有这些不同的更新。
React想弄清楚它是否能把所有这些更新都堆叠在一起,也许有更优化的方式来更新这些组件,使其性能更高,这就是React在幕后所做的,因此,设置状态调用是异步调用。

lpwwtiir

lpwwtiir9#

简而言之,此. setState({数据:value})本质上是异步的,这意味着它将移出调用堆栈,并且只有在得到解析后才会返回调用堆栈。
请阅读事件循环,以清楚了解JS中的异步特性以及为什么更新需要时间-

    • 一个

因此-

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);
    });

相关问题