[英]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.