为了账号安全,请及时绑定邮箱和手机立即绑定

React:如何避免使用始终返回相同值但更改其内部状态的钩子重新渲染组件

React:如何避免使用始终返回相同值但更改其内部状态的钩子重新渲染组件

慕村225694 2023-07-20 16:38:22
想象一下这个钩子每秒都会改变他的值,如果随机值是 5 的倍数则返回 true,否则返回 false。我该怎么做才能停止每秒重新渲染?PS:我尝试使用 useMemo 和 useRef 始终返回相同的对象,但它仍在重新渲染。请帮忙const useRandomIs5x = () => {  const [state, setState] = useState(0);  useEffect(() => {    const t0 = setInterval(() => {      setState(getRandomValue())    }, 1000)    return () => clearInterval(to)  }, [])  return state % 5 === 0;}const Root = () => {  const bool = useRandomIs5x();  console.log("I'm re-rendering every second", bool)  return <div>test</div>}
查看完整描述

4 回答

?
梵蒂冈之花

TA贡献1900条经验 获得超5个赞

我相信如果没有一些解决方法,这几乎是不可能实现的。要调用setState或不调用,我们必须访问当前状态值。如果我们传入state依赖数组,这是可能的。但随后,该间隔将每秒重新创建。


也可以使用 refs 来实现,但是目前还没有正确的方法来监听ref 的更改。


更新:看起来它可以很好地用作useRef以前的数据持有者。感谢安豪2。


const { useEffect, useState, useRef } = React;


const useRandomIs5x = () => {

  const [state, setState] = useState(true);

  const ref = useRef(null);

  

  useEffect(() => {

    const t0 = setInterval(() => {

      const value = Math.floor(Math.random() * 5) % 5 === 0;

      if (value === ref.current) return;

      ref.current = value;

      setState(value);

    }, 1000);


    return () => clearInterval(t0);

  }, []);


  return state;

}


const Root = () => {

  const bool = useRandomIs5x();

  console.log('re-render!', bool);

  return <div>test</div>

}


ReactDOM.render(<Root />, document.getElementById("root"));

<script src="https://unpkg.com/react@16/umd/react.development.js"></script>

<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>


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


查看完整回答
反对 回复 2023-07-20
?
皈依舞

TA贡献1851条经验 获得超3个赞

我可以使用这个库react-hooks-in-callback来解决这个问题, 将钩子与组件隔离。


查看完整回答
反对 回复 2023-07-20
?
料青山看我应如是

TA贡献1772条经验 获得超8个赞

您可能需要采取一些不同的方法。你不需要随机值,你想要它是否能被 5 整除。所以这就是状态并从钩子返回的内容。随机值只能作为参考。所以尝试这样的事情(代码未经测试,但应该给你一个总体思路):


const useRandomIs5x = () => {

    const [divisibleBy5, setDivisibleBy5] = useState(true);

    const randomValue = useRef(0);


    useEffect(() => {

        const t0 = setInterval(() => {

            // Set the new random value into a ref so as to not cause re-render

            randomValue.current = getRandomValue();


            const randIsDivisibleBy5 = randomValue.current % 5 === 0;


            // Only if it changes do we update the boolean state and trigger re-render

            if (randIsDivisibleBy5 !== divisibleBy5) {

                setDivisibleBy5(randIsDivisibleBy5);

            }

        }, 1000);

        

        return () => clearInterval(to);

    }, []);


    // Return the boolean state value instead

    return divisibleBy5;

}


查看完整回答
反对 回复 2023-07-20
?
临摹微笑

TA贡献1982条经验 获得超2个赞

我们最好更改状态来存储 is5x 而不是值。一种可能的解决方案是使用 useRef 来检查我们是否应该每秒更新该值。然后,同步 useRef 和状态值。


const useRandomIs5x = () => {

  const [state, setState] = useState(false);

  const prevIs5x = useRef(false);

  useEffect(() => {

    const t0 = setInterval(() => {

      const is5x = getRandomValue() % 5 === 0;

      const isDiff = is5x !== prevIs5x.current;

      prevIs5x.current = is5x;

      if (isDiff) {

        setState((prevState) => !prevState);

      }

    }, 1000);

    return () => clearInterval(t0);

  }, []);

  return state;

};


查看完整回答
反对 回复 2023-07-20
  • 4 回答
  • 0 关注
  • 187 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信