![](/img/trans.png)
[英]React - How to update the state in useEffect without causing an infinite loop?
[英]How To Pass State Update To Custom Render Loop In React's `useEffect`?
我經常遇到這樣的情況,我構建了一個基於window.requestAnimationFrame
的渲染循環,但是想要在循環內部交換一些狀態。 有幾種方法可以做到這一點,但我不確定哪種方法最好。 我的設置通常是這樣的:
function Animation({someState}) {
const loopDataRef = useRef();
useEffect(() => {
//do something initialization work for the renderloop, e.g. getContext, etc.
let frame;
const loop = (cts) => {
frame = window.requestAnimationFrame(loop)
//do some loop work using someState and loopDataRef.current
}
loop();
return () => window.cancelAnimationFrame(frame);
}, []);
}
請注意,在循環中使用someState
將始終使用效果的最后一次運行的值,不一定是當前值。 以下是一些顯而易見的解決方案:
我可以將someState
放在 useEffect 的依賴數組中,這樣只要useEffect
發生變化,循環就會重新啟動。 但是如果初始化很昂貴,例如使用 WebGL,我在那里創建所有紋理並編譯着色器,它似乎不是很優雅。
我可以使用兩種效果,一種用於循環本身的初始化,另一種僅用於循環,它在每次 state 更改時停止和啟動。 但我仍然認為,理想情況下,animation 循環應該一直運行到停止,而不是在其間停止/啟動。
另一個具有兩種效果的解決方案,但這次我執行const someStateRef = useRef()
然后在其依賴數組中使用someState
創建一個效果,它只是將someState
寫入someStateRef.current
因此我可以在循環中使用它。 這是我實現它的示例。 或者,可以在每次渲染時將someState
寫入someStateRef.current
,而不會產生其他影響。 看起來非常高效,但不是很優雅。
最 React 的方式是什么?
我將 go 與您已經實施的第三個選項,因為它看起來與 React Hooks FAQ(第三個代碼塊)中的一個示例完全一樣:
function Example(props) {
// Keep latest props in a ref.
const latestProps = useRef(props);
useEffect(() => {
latestProps.current = props;
});
useEffect(() => {
function tick() {
// Read latest props at any time
console.log(latestProps.current);
}
const id = setInterval(tick, 1000);
return () => clearInterval(id);
}, []); // This effect never re-runs
}
(將set/clearInterval
替換為request/cancelAnimationFrame
)
為了完整起見:前兩個選項存在您提到的缺陷,不建議在每次渲染時將someStateRef.current
寫入someState
而沒有其他效果。
避免在渲染期間讀取和更新引用,因為這會使組件的行為難以預測和理解。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.