在计时器回调函数中更改时未修改 React 数组

React array not modified when changed in a timer callback function

以下代码显示项目列表。该列表保存在状态变量 list 中。有两种方法可以将项目添加到列表中:通过单击 Inc 按钮手动添加,或者通过启动计时器每 1 秒将项目添加到列表中。

Inc 按钮有效,但定时器功能无效。检查计时器函数时,状态变量 list 似乎不会在调用之间保持其新长度。

这是为什么?感谢阅读。

import React, { useState } from 'react';

export function Tester() {

    const [list, setList] = useState([]);

    var timer = null;


    function startTimer() {

        // Start a timer
        if (timer == null)
            timer = setTimeout(timeoutCallback, 1000);

    }

    function timeoutCallback() {

        //
        timer = null;

        //
        btnClicked();

        //
        startTimer();

    }

    function btnClicked() {

        let today = new Date();
        let strTime = today.getHours() + ':' + today.getMinutes() + ':' + today.getSeconds();

        setList([
            ...list,
            {
                name: "item " + strTime,
                id: list.length + 1
            }
        ]);

    }


    const renderedItems = list.map(
        X => {
            return <span key={X.id}>{X.id}+{X.name} </span>
        }
    );

    return (
        <>TESTER
            <button onClick={startTimer}>Timer</button>         
            <button onClick={btnClicked}>Inc</button>
            {renderedItems}
        </>
    );

}

您需要向 setList 提供回调,该回调采用列表的先前状态值并计算新值,因为 list 的值将过时。

      setList((prevList) => [
          ...prevList,
          {
              name: "item " + strTime,
              id: prevList.length + 1
          }
      ]);

另外,当 timer 的当前值发生变化时,您需要使用 useRef 在渲染之间持久化计时器实例而不触发新的重新渲染。

  const timer = useRef(null);


  function startTimer() {

      // Start a timer
      if (timer.current == null)
          timer.current = setTimeout(timeoutCallback, 1000);

  }

  function timeoutCallback() {

      //
      timer.current = null;

      //
      btnClicked();

      //
      startTimer();

  }