簡體   English   中英

React:如何避免使用鈎子重新渲染組件,該鈎子始終返回相同的值但會改變其內部狀態

[英]React: how to avoid re-rendering a component with a hook that returns always the same value but changes its inner state

想象一下,這個鈎子每秒都會改變他的值,如果隨機值是 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> }

我相信如果沒有一些變通辦法,這幾乎是不可能的。 無論是否調用setState ,我們都必須訪問當前狀態值。 如果我們在依賴數組中傳遞state ,這是可能的。 但是,間隔將每秒重新創建。

它也可以用 refs 來實現,但是(目前)還沒有正確的方法來監聽ref 的變化。

更新:看起來使用useRef作為以前的數據持有者可以正常工作。 感謝 anhau2。

 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>

PS期待如何處理它的任何其他想法。

您可能需要以不同的方式處理它。 你不想要隨機值,你想要它是否可以被 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;
}

我們最好將狀態更改為存儲 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;
};

我可以使用這個庫react-hooks-in-callback將鈎子與組件隔離來解決這個問題。

檢查這個沙箱示例

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM