setState在intervalRef内部不会更新。

huangapple go评论76阅读模式
英文:

setState does not update inside intervalRef

问题

以下是您要翻译的代码部分:

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'));

请注意,代码中使用了React库的相关部分,这些部分不会被翻译。如果您有任何其他问题或需要进一步帮助,请随时告诉我。

英文:

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.

<!-- begin snippet: js hide: false console: true babel: true -->

<!-- language: lang-js -->

const {useState,useEffect,useRef} = React;

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

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


ReactDOM.render(&lt;Main /&gt;, document.getElementById(&#39;app&#39;));

<!-- language: lang-html -->

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;

&lt;div id=&quot;app&quot;&gt;&lt;/div&gt;

<!-- end snippet -->

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

答案1

得分: 0

由于useEffect不依赖于count,所以闭包内的count始终为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); // 清理函数
    },
    [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"));
英文:

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.

<!-- begin snippet: js hide: false console: true babel: true -->

<!-- language: lang-js -->

const { useState, useEffect, useRef } = React;

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

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

ReactDOM.render(&lt;Main /&gt;, document.getElementById(&quot;app&quot;));

<!-- language: lang-html -->

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;

&lt;div id=&quot;app&quot;&gt;&lt;/div&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2020年1月3日 16:18:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/59575205.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定