每 5 秒就會有一些來自長輪詢的數據,我希望我的元件在每次數組的一項(或數組長度本身)發生變化時調度一個操作。 在將陣列作為依賴項傳遞給 useEffect 時,如何防止 useEffect 進入無限循環,但如果任何值發生變化,仍然設法調度一些操作?
useEffect(() => { console.log(outcomes) }, [outcomes])
其中 outcomes
是一個 ID 數組,例如 [123, 234, 3212]
。數組中的項目可能會被替換或刪除,因此數組的總長度可能(但不一定)保持不變,因此傳遞 outcomes.length
作為依賴項並非如此。
outcomes
來自 reselect 的自訂選擇器:
const getOutcomes = createSelector( someData, data => data.map(({ outcomeId }) => outcomeId) )
P粉4642089372023-10-18 15:49:11
使用 JSON.stringify() 或任何深度比較方法可能效率較低,如果您事先知道物件的形狀,您可以編寫自己的效果鉤子來根據結果觸發回調您的自訂相等函數。
useEffect
的工作原理是檢查相依性陣列中的每個值是否與前一渲染中的值相同,如果其中一個不是,則執行回呼。因此,我們只需要使用 useRef
保留我們感興趣的資料實例,並且僅在自訂相等性檢查返回 false
時指派一個新實例來觸發效果。
function arrayEqual(a1: any[], a2: any[]) { if (a1.length !== a2.length) return false; for (let i = 0; i < a1.length; i++) { if (a1[i] !== a2[i]) { return false; } } return true; } type MaybeCleanUpFn = void | (() => void); function useNumberArrayEffect(cb: () => MaybeCleanUpFn, deps: number[]) { const ref = useRef(deps); if (!arrayEqual(deps, ref.current)) { ref.current = deps; } useEffect(cb, [ref.current]); }
function Child({ arr }: { arr: number[] }) { useNumberArrayEffect(() => { console.log("run effect", JSON.stringify(arr)); }, arr); return{JSON.stringify(arr)}; }
更進一步,我們也可以透過建立一個接受自訂相等函數的效果鉤子來重複使用該鉤子。
type MaybeCleanUpFn = void | (() => void); type EqualityFn = (a: DependencyList, b: DependencyList) => boolean; function useCustomEffect( cb: () => MaybeCleanUpFn, deps: DependencyList, equal?: EqualityFn ) { const ref = useRef(deps); if (!equal || !equal(deps, ref.current)) { ref.current = deps; } useEffect(cb, [ref.current]); }
useCustomEffect( () => { console.log("run custom effect", JSON.stringify(arr)); }, [arr], (a, b) => arrayEqual(a[0], b[0]) );
P粉6628028822023-10-18 12:32:21
您可以傳遞 JSON.stringify(outcomes)
作為依賴項清單:
了解更多此處
#useEffect(() => { console.log(outcomes) }, [JSON.stringify(outcomes)])