为什么使用 React Hooks useState() 的计数会在两个数字之间交替?

Why does a count using React Hooks useState() alternate between two numbers?

以下是使用useState()的React Hooks实验。它工作正常,除非单击 + 按钮,然后数字可以从 70017000 交替,然后在一些数字之间快速闪烁。

实际上,在不点击 + 的情况下,数字表现良好,但达到大约 8000 或 9000,然后它可能会开始在某些数字之间闪烁。为什么会这样,如何解决?

P.S. 初步调试发现: Counter() 好像被调用了多次,每次都设置了一个Interval Timer。所以 "magically",似乎 useState() 运行 只有一次——出于某种未知的神奇原因——或者它可能 运行 不止一次,但只是返回了完全相同的内容每次都是为了某种神奇的机制。 0的初值还真是第一次这样。当它在未来的时候是 useState(0) 时,count 不是 0...要么。

function Counter() {
    const [count, setCount] = React.useState(0);

    setInterval(() => {
        setCount(count + 1000);
    }, 1000);

    return (
        <div>
            <button onClick={() => setCount(count + 1)}> + </button>                    
            { count }
            <button onClick={() => setCount(count - 1)}> - </button> 
        </div>
    );
}

ReactDOM.render(<Counter />, document.querySelector("#root"));
button { margin: 0 1em }
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>

<div id="root"></div>

对 'why is that' 不太确定,但已通过在按钮中替换 setCount(c => c + 1) 和在间隔中替换 setCount(c => c + 1000) 来解决。

将'setInterval'放在一个效果中也确保只有一个间隔...

  React.useEffect(() => {  
     setInterval(() => {
        setCount(c => c + 1000);
     }, 1000);
  },[])

PS Counter() 在每次渲染时都会被调用,我认为...而 useState 每次安装只被调用一次.

  1. 功能组件中的代码在每次重新渲染组件时都会执行。因此,在每次重新渲染时,您都会启动一个无限计时器,该计时器每秒增加 1000 来计数
  2. 每次您更改组件的状态时,React 都会重新渲染它。意思是,每次执行 setCount 都会导致新的重新渲染并启动新的计时器
  3. 此外,setCount 是异步的,如果您需要依赖前一个状态来确定下一个状态,您应该调用回调,就像在其他答案中演示的那样 (setCount(c => c + 1))

这样的事情应该有效:

import React, {useState, useRef, useEffect} from 'react';

function Counter() {
    const [count, setCount] = useState(0);
    //useRef gives us an object to store things between re-renders
    const timer = useRef();

    useEffect(() => {
      timer.current = setInterval(() => {
        setCount(count => count + 1000);
      }, 1000);

      //If we return a function, it will be called when component is dismounted
      return () => {
        clearInterval(timer.current);
      }
    }, []);

    return (
        <div>
            <button onClick={() => setCount(count => count + 1)}> + </button>                    
            { count }
            <button onClick={() => setCount(count => count - 1)}> - </button> 
        </div>
    );
}