[英]how to handle rest arguments and function in useeffect causing re-render
說我有這樣的功能:
export const usePagedGetAll = <R, Args extends any[]>(
baseUrl: string,
...args: Args
) => {
const fn = useWrappedRemoteCall(
async () => {
return await fetchRequest<RemoteData<R>>(url, options);
}
);
useEffect(() => {
(async () => {
await fn.execute(...args);
})();
}, [args, fn, paginationInfo.skip, paginationInfo.take]);
return fn
};
問題是args
每次都是一個新的數組,所以如果它在deps數組中就會發生無限的重新渲染。 如果元素發生變化,我確實希望它重新渲染。
同樣適用於fn
函數,它每次都是新的,因此它將導致無限重新渲染,我該怎么辦。
我可以停止應用修復的鈎子eslint規則
useEffect(() => {
(async () => {
await fn.execute(...args);
})();
// eslint-disable-next-line
}, [paginationInfo.skip, paginationInfo.take]);
但這似乎是一個普遍的問題
根據您的需要,我將依賴關系分為兩部分進行分析。
args
是一個數組,每次都是全新的。
考慮創建一個useCustorCompareEffect
。 通過自定義比較功能。 僅當指定的值更改時,才會觸發effect
。
const useCustorCompareEffect = (callback, value, compare) => {
const prev = useRef({ init: true, value })
useEffect(() => {
const { current } = prev
if (current.init) {
callback()
current.init = false
} else {
if (!compare || !compare(value, current.value)) {
callback()
current.value = value
}
}
}, [callback, value, compare])
}
const useDemo=()=>{
const compare = useCallback((curr, prev) => {
// Compare functions, return comparison results, use `useCallback` to prevent triggering `effect` due to compare
}, [])
useCustorCompareEffect(
() => {
...
},
[data],
compare,
)
}
要將函數用作依賴項,可以將函數定義包裝在useCallback
,然后在useCallback
定義此函數所需的依賴useCallback
。
const execute = useCallback(() => {
console.log('update')
}, [])
useEffect(() => {
execute()
}, [execute);
在你的情況下,被另一個獲得你的函數useWrappedRemoteCall
,這需要使用useCallback
包execute
的定義useWrappedRemoteCall
,然后返回。 另外,如果只在useEffect
使用execute
, useEffect
需要提取execute
然后使用execute
作為依賴項。 防止fn中的其他數據更改觸發effect
const useWrappedRemoteCall = () => {
const execute = useCallback(() => {
console.log('update')
}, [])
return { execute }
}
const usePagedGetAll = () => {
const { execute } = useWrappedRemoteCall()
useEffect(() => {
execute()
}, [execute])
}
如果還有其他特殊情況,請告訴我。
您可以使用useRef
編寫一個自定義鈎子來深入檢查args
。
function usePrevious(value) {
const ref = React.useRef(null);
if(value != ref.current) {
// ...
// check if they are the same here else update ref.current
// ...
ref.current = value;
}
return ref.current;
}
然后在useMemo
包裝useWrappedRemoteCall
函數,因為它返回一個對象。
const fn = React.useMemo(() => useWrappedRemoteCall(
async () => {
return await fetchRequest<RemoteData<R>>(url, options);
}
), [url, options, fetchRequest]);
最后結果:
export const usePagedGetAll = <R, Args extends any[]>(
baseUrl: string,
...args: Args
) => {
// use previous args if unmodified
args = usePrevious(args);
// useMemo to memoize the object returned by useWrappedRemoteCall
const fn = React.useMemo(() => useWrappedRemoteCall(
async () => {
return await fetchRequest<RemoteData<R>>(url, options);
}
), [url, options, fetchRequest]);
React.useEffect(() => {
(async () => {
await fn.execute(...args);
})();
}, [args, fn, paginationInfo.skip, paginationInfo.take]);
return fn
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.