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

想象一下这个钩子每秒都会改变他的值,如果随机值是 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>

}


慕村225694
浏览 188回答 4
4回答

梵蒂冈之花

我相信如果没有一些解决方法,这几乎是不可能实现的。要调用setState或不调用,我们必须访问当前状态值。如果我们传入state依赖数组,这是可能的。但随后,该间隔将每秒重新创建。也可以使用 refs 来实现,但是目前还没有正确的方法来监听ref 的更改。更新:看起来它可以很好地用作useRef以前的数据持有者。感谢安豪2。const { useEffect, useState, useRef } = React;const useRandomIs5x = () => {&nbsp; const [state, setState] = useState(true);&nbsp; const ref = useRef(null);&nbsp;&nbsp;&nbsp; useEffect(() => {&nbsp; &nbsp; const t0 = setInterval(() => {&nbsp; &nbsp; &nbsp; const value = Math.floor(Math.random() * 5) % 5 === 0;&nbsp; &nbsp; &nbsp; if (value === ref.current) return;&nbsp; &nbsp; &nbsp; ref.current = value;&nbsp; &nbsp; &nbsp; setState(value);&nbsp; &nbsp; }, 1000);&nbsp; &nbsp; return () => clearInterval(t0);&nbsp; }, []);&nbsp; return state;}const Root = () => {&nbsp; const bool = useRandomIs5x();&nbsp; console.log('re-render!', bool);&nbsp; 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>

皈依舞

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

料青山看我应如是

您可能需要采取一些不同的方法。你不需要随机值,你想要它是否能被 5 整除。所以这就是状态并从钩子返回的内容。随机值只能作为参考。所以尝试这样的事情(代码未经测试,但应该给你一个总体思路):const useRandomIs5x = () => {&nbsp; &nbsp; const [divisibleBy5, setDivisibleBy5] = useState(true);&nbsp; &nbsp; const randomValue = useRef(0);&nbsp; &nbsp; useEffect(() => {&nbsp; &nbsp; &nbsp; &nbsp; const t0 = setInterval(() => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Set the new random value into a ref so as to not cause re-render&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; randomValue.current = getRandomValue();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const randIsDivisibleBy5 = randomValue.current % 5 === 0;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Only if it changes do we update the boolean state and trigger re-render&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (randIsDivisibleBy5 !== divisibleBy5) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setDivisibleBy5(randIsDivisibleBy5);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }, 1000);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; return () => clearInterval(to);&nbsp; &nbsp; }, []);&nbsp; &nbsp; // Return the boolean state value instead&nbsp; &nbsp; return divisibleBy5;}

临摹微笑

我们最好更改状态来存储 is5x 而不是值。一种可能的解决方案是使用 useRef 来检查我们是否应该每秒更新该值。然后,同步 useRef 和状态值。const useRandomIs5x = () => {&nbsp; const [state, setState] = useState(false);&nbsp; const prevIs5x = useRef(false);&nbsp; useEffect(() => {&nbsp; &nbsp; const t0 = setInterval(() => {&nbsp; &nbsp; &nbsp; const is5x = getRandomValue() % 5 === 0;&nbsp; &nbsp; &nbsp; const isDiff = is5x !== prevIs5x.current;&nbsp; &nbsp; &nbsp; prevIs5x.current = is5x;&nbsp; &nbsp; &nbsp; if (isDiff) {&nbsp; &nbsp; &nbsp; &nbsp; setState((prevState) => !prevState);&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }, 1000);&nbsp; &nbsp; return () => clearInterval(t0);&nbsp; }, []);&nbsp; return state;};
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript