setState 不会在 intervalRef 内更新 [英] setState does not update inside intervalRef

查看:44
本文介绍了setState 不会在 intervalRef 内更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

const {useState,useEffect,useRef} = React;功能定时器({active}){const intervalRef = useRef(null)const [count, setCount] = useState(0)useEffect(()=>{如果(活动){intervalRef.current = setInterval(()=>{控制台日志(计数);设置计数(计数 + 1);},100)} 别的 {clearInterval(intervalRef.current)}},[积极的])返回 (<p>{count}</p>)}函数主(){const [active, setActive] = useState(false)返回 (<div><Timer active={active}/><button onClick={()=>{setActive(!active)}}>切换</button>

)}ReactDOM.render(

, 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 不起作用?

解决方案

由于useEffect不依赖于countcount里面的闭包始终为 0,并且 0 + 1 -> 1.使用 updater 函数 当您调用 setState 时.使用当前状态调用更新函数.

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

const { useState, useEffect, useRef } = React;功能定时器({ 活动}){const intervalRef = useRef(null);const [count, setCount] = useState(0);使用效果(() =>{如果(活动){intervalRef.current = setInterval(() => {setCount(count => count + 1);}, 100);} 别的 {clearInterval(intervalRef.current);}返回 () =>clearInterval(intervalRef.current);//清理函数},[积极的]);返回<p>{count}</p>;}函数主(){const [active, setActive] = useState(false);返回 (<div><Timer active={active}/><button onClick={() =>{ setActive(!active);}}>切换</button>

);}ReactDOM.render(

, 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>

I'm trying to learn how to use intervalRef where I increment the state ever 100 ms, but for some reason it does not work.

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>

The interval works completely fine since the console.log(count) prints ok, but why doesn't setCount work?

解决方案

Since the useEffect is not dependant on count, the count inside the closure is always 0, and 0 + 1 -> 1. Use an updater function when you call setState. The update function is called with the current state.

Note: you should also return a cleanup function from useEffect, that will clear the interval if the component is unmounted.

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>

这篇关于setState 不会在 intervalRef 内更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆