首页 > 解决方案 > setState 不会在 intervalRef 内更新

问题描述

我正在尝试学习如何使用 intervalRef 来增加状态每 100 毫秒,但由于某种原因它不起作用。

const {useState,useEffect,useRef} = React;

function Timer({active}) {
    const intervalRef = useRef(null)
    const [count, setCount] = useState(0)
    useEffect(()=>{
        if(active){
            intervalRef.current = setInterval(()=>{
                console.log(count);
                setCount(count + 1);
            },100)
        } else {
            clearInterval(intervalRef.current)
        }
    },[active])
    return (
        <p>{count}</p>
    )
}

function Main() {
    const [active, setActive] = useState(false)
    return (
        <div>
            <Timer active={active}/>
            <button onClick={()=>{setActive(!active)}}>Toggle</button>
        </div>
    )
}


ReactDOM.render(<Main />, document.getElementById('app'));
<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="app"></div>

由于console.log(count)打印正常,因此间隔工作得很好,但为什么 setCount 不起作用?

标签: reactjsreact-hooks

解决方案


由于useEffect不依赖于countcount因此闭包内部始终为 0,并且 0 + 1 -> 1。调用时使用更新函数setState。使用当前状态调用更新函数。

注意:您还应该从 中返回一个清理函数useEffect,如果组件被卸载,它将清除间隔。

const { useState, useEffect, useRef } = React;

function Timer({ active }) {
  const intervalRef = useRef(null);
  const [count, setCount] = useState(0);
  useEffect(
    () => {
      if (active) {
        intervalRef.current = setInterval(() => {
          setCount(count => count + 1);
        }, 100);
      } else {
        clearInterval(intervalRef.current);
      }
      
      return () => clearInterval(intervalRef.current); // cleanup function
    },
    [active]
  );
  return <p>{count}</p>;
}

function Main() {
  const [active, setActive] = useState(false);
  return (
    <div>
      <Timer active={active} />
      <button onClick={() => { setActive(!active); }}>Toggle</button>
    </div>
  );
}

ReactDOM.render(<Main />, document.getElementById("app"));
<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="app"></div>


推荐阅读