关于更新useState的奇怪问题

huangapple go评论70阅读模式
英文:

A strange problem about updating useState

问题

这是我的代码:

const { useState, useEffect } = React;

function App() {
  let [count, setCount] = useState(0);
  let [num, setNum] = useState(0);

  useEffect(() => {
    setCount((pre) => {
      return pre + 1;
    });
    setNum(num + 1);
  }, []);

  return (
    <p>
      count:{count} num:{num}
    </p>
  );
}

ReactDOM.createRoot(document.querySelector("#app")).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

结果是:count:2 num:1! 为什么?

理论上,num 和 count 应该是同步的,我不知道发生了什么!

在开发模式下,useEffect 的回调被执行了两次。

英文:

Here is my code :

<!-- begin snippet: js hide: false console: true babel: true -->

<!-- language: lang-js -->

const {useState, useEffect} = React;

function App() {
   let [count, setCount] = useState(0);
   let [num, setNum] = useState(0);

   useEffect(() =&gt; {
       setCount((pre) =&gt; {
           return pre + 1;
       });
       setNum(num + 1);
   }, []);

   return (
     &lt;p&gt;
         count:{count} num:{num}
     &lt;/p&gt;
  );
}


ReactDOM.createRoot(document.querySelector(&quot;#app&quot;))
  .render(&lt;React.StrictMode&gt;&lt;App /&gt;&lt;/React.StrictMode&gt;);

<!-- language: lang-html -->

&lt;script crossorigin src=&quot;https://unpkg.com/react@18/umd/react.development.js&quot;&gt;&lt;/script&gt;
&lt;script crossorigin src=&quot;https://unpkg.com/react-dom@18/umd/react-dom.development.js&quot;&gt;&lt;/script&gt;
&lt;div id=&quot;app&quot;&gt;&lt;/div&gt;

<!-- end snippet -->

The result is : count:2 num:1! why?

In theory, num and count should be synchronous, I don't know what happend!<br>
In dev mode, useEffect's callback executed twice.

答案1

得分: 2

这是由于StrictMode的原因:

Strict Mode仅在开发环境中运行,不会妨碍生产构建。它会记录额外的警告或错误,并调用函数两次以确保始终出现预期的结果。

你可能会想为什么它们具有不同的值,以及你认为它们应该是相同的,要么是1,要么是2。

这是因为当你使用类似于count的函数来更新状态值时:

setCount((pre) => {
   return pre + 1;
});

这将使状态更新基于它之前的值,而不是基于它在上一次渲染中的值,这就是为什么我们使用useState的函数,以便在下一次渲染之前访问状态的先前值,并在组件重新渲染之前再次更新它,就像在这个示例中发生的那样。

因此,在这里,第二次useEffect运行(因为StrictMode),pre等于1,所以最终值将是2

然而,当你以这种方式更新你的状态:

setNum(num + 1);

它将基于num进行更新,而num仍然等于0,因为组件尚未重新渲染。

英文:

This is because of StricMode :
>Strict Mode only runs in development, which does not impede the production build. It logs extra warnings or errors and invokes functions twice to ensure that the expected results always occur

you may wonder why they have different values and you think that they should have the same, either 1 or 2 <br>

This is because when you update a state value with the function like you did for count :

setCount((pre) =&gt; {
   return pre + 1;
});

This will make the state updates based on it previous values not based on its value in the last render <br> and this is why we use the function of useState so to have access to the previous value of the state before the next render and we can also update it again just before the component rerenders as it happend in this example

So here the second time useEffect runs (because of strictMode) pre is equal to 1 so the final value will be 2.<br>
However when you update your state this way :

setNum(num + 1);

It will be updated based on num and num is still equal to 0 because the component didn't rerendered yet

答案2

得分: 0

代码部分不需要翻译,以下是翻译好的内容:

这背后的主要原因是StrictMode
StrictMode 会在开发环境中将组件渲染两次(但在生产环境中不会),以便检测代码中的任何问题并提出警告(这可能非常有用)。

如果您想摆脱这一点,请将

ReactDOM.render(
    <React.StrictMode>
      {app}
    </React.StrictMode>,
    document.getElementById('root')
);

更改为

ReactDOM.render(
  {app}
  document.getElementById('root')
);
英文:

The prime reason behind this is StrictMode
> StrictMode renders components twice (on dev but not production) in order to detect any problems with your code and warn you about them (which can be quite useful).

If you want to get rid of this, change

 ReactDOM.render(
     &lt;React.StrictMode&gt;
       {app}
     &lt;/React.StrictMode&gt;,
    document.getElementById(&#39;root&#39;)
  );

to

  ReactDOM.render(
    {app}
    document.getElementById(&#39;root&#39;)
  );

huangapple
  • 本文由 发表于 2023年3月1日 10:08:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/75598956.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定