【问题标题】:understanding weird setState behaviour in reactjs using useState hooks使用 useState 钩子理解 reactjs 中奇怪的 setState 行为
【发布时间】:2021-03-02 01:50:43
【问题描述】:
const[count,setcount]=useState(0)
function inc() {
setcount(count + 5);
setcount(count + 5);
setcount(count + 5);
setcount(count + 5);
}
return (
<div>
  <h1>{count}</h1> #output =5
  <button onClick={() => inc()}>clickme</button>
</div>
);




}
function inc() {
setcount(count=>count + 5);
setcount(count=>count + 5);
setcount(count=>count + 5);
setcount(count=>count + 5);
}
return (
<div>
  <h1>{count}</h1> #output =5
  <button onClick={() => inc()}>clickme</button>
</div>
);
}

当我调用第一个函数时,按钮点击计数值变为 5,而在第二个函数中变为 20。我不知道为什么会出现这种行为

【问题讨论】:

    标签: reactjs react-hooks state use-state


    【解决方案1】:

    仅仅因为这些变量是从 React 钩子返回的,并不会使它们的行为与任何其他 JS 变量不同。 const 是常数;它不能改变。考虑以下没有 React 的示例。

    function logValue(input) {
      console.log(input);
    }
    
    const value = 0;
    
    logValue(value + 5);
    logValue(value + 5);
    logValue(value + 5);

    它每次记录 5 个。这是你所期望的对吗?因为value 是常量并且始终为0。您可能会认为这不一样,因为您没有记录,您正在更新。但真的不一样。状态更新函数不只是更新像count = 5 这样的变量(提示:它会中断,见下文)。

    const value = 0;
    
    function updateValue(input) {
      value = input;
    }
    
    updateValue(value + 5);

    相反,它会跟踪下一次渲染时的值应该是什么,并且当再次调用函数组件时,会为有状态的 const 分配新值。

    因此,即使您多次调用 updater 函数,您发送它进行更新的值也是总是 5。

    关于功能更新(setCount(count =&gt; count + 5)),这里的count 不是指状态常量,而是指参数count(命名让人困惑,因为状态变量被参数遮蔽)。这个参数是guaranteed to contain the most recent value of state(帮助解决异步限制)。这就是第二组按预期工作的原因。

    这里有一个更完整的示例,其中的日志显示了实际调用事物的时间,以及它们在整个过程中的值:

    const {useState, useEffect} = React;
    
    const Example = () => {
      const [count, setCount] = useState(0);
      
      const regularUpdate = () => {
        console.log('count before update:', count);
        setCount(count + 5);
        console.log('count after 1 update:', count);
        setCount(count + 5);
        console.log('count after 2 updates:', count);
        setCount(count + 5);
        console.log('count after 3 updates:', count);
      }
      
      const functionalUpdate = () => {
        console.log('count before update:', count);
        setCount(count => {
          console.log('count inside 1st update:', count);
          return count + 5
        });
        setCount(count => {
          console.log('count inside 2nd update:', count);
          return count + 5
        });
        setCount(count => {
          console.log('count inside 3rd update:', count);
          return count + 5
        });
        console.log('count after updates:', count);
      }
      
      return (
        <div>
          <h1>Count: {count}</h1>
          <button onClick={regularUpdate}>Run normal updates</button>
          <button onClick={functionalUpdate}>Run functional updates</button>
          <button onClick={() => {setCount(0); console.clear();}}>Reset</button>
        </div>
      );
    }
    
    ReactDOM.render(<Example />, document.getElementById('root'));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
    <div id="root"></div>

    在运行功能更新时需要注意日志的顺序。请注意,“更新后计数”会记录之前功能更新的任何内部日志,并且它仍然保留未更新的值。

    【讨论】:

      【解决方案2】:

      setcount 是异步方法,因此第一个inc() 方法的count (0) 的初始值将同时执行4 个setcounts。所以结果将是 5 甚至 4 setcounts 被执行。

      对于第二个inc()方法,它使用的函数将接收之前的值,并返回一个更新的值,所以结果是预期的20。

      【讨论】:

      • 如果我有最后一条语句 setCount(count+10) 它会覆盖状态值,为什么?
      • 结果将是 10
      • 为什么会这样?
      • setCount(count+5); setCount(count+10); 当这两个命令准备好执行时,参数count 将是相同的值。因为 setCount 是异步方法。
      • 命令会同步执行,setCount(count+5)会比setCount(count+10)先执行一点,所以setCount(count+10)会完成一点晚于 setCount(count+5)
      猜你喜欢
      • 2021-04-14
      • 1970-01-01
      • 2021-08-01
      • 2020-04-26
      • 1970-01-01
      • 2019-10-20
      • 2012-08-20
      • 2020-06-22
      • 2020-12-17
      相关资源
      最近更新 更多