我有如下的useDidUpdateEffect鉤子
span class="hljs-keyword">import { useRef, useEffect } from "react"。
export default function useDidUpdateEffect(effect, deps) {
const didMount = useRef(false)。
useEffect(() => {
if (didMount.current) {
effect()。
} else {
didMount.current = true;
}
}, deps);
}
而我目前的使用情況如下:
useDidUpdateEffect(() => { ... }, [JSON.stringify(complexNestedObject)] )。
問題是,由于我的dep是復雜和深入的,有時回呼被執行而沒有必要。
對于useEffect,我有一個解決方案,那就是useDeepEffect:
我有一個解決方案。
span class="hljs-keyword">import { useRef, useEffect } from "react"。
import { isEqual } from "lodash";
export default function useDeepEffect(effect。deps = undefined) {
const isFirst = useRef(true)。
const prevDeps = useRef(deps);
useEffect(() => {
const isSame = prevDeps.current.every((obj, index) =>
isEqual(obj, deps[index])
);
if (isFirst.current || !isSame) {
effect()。
}
isFirst.current = false;
prevDeps.current = deps;
}, deps)。
}
但是我想不出有什么辦法可以用useDidUpdateEffect做一個深度比較,而不需要創建另一個鉤子。
有什么想法嗎?
====================
Update:
我之所以會出現目前這種情況,是因為這種情況。也許這可以做得更簡單,但說實話,我已經盡力了(我不是超級專業的)
。
我有一個檔案夾 "api",里面有不同的模塊,包含了連接到我的服務器的不同功能(我沒有在這一部分使用鉤子 這一部分)
services/
firebase/
api/
用戶/
幫助器/
cache/
usersCache.js。
index.js。
...
正如你所看到的,我有一個模塊 "usersCache.js"(記憶化模式),這將避免一些RTT,降低成本。為了避免RAM的問題,我在那里實作了一個快取演算法 "LRU"。
- 在我的應用程式中,我沒有使用REDUX(也許是我所采取的最糟糕的想法,但要適應它已經太晚了,90%的作業已經完成。我將嘗試學習 這個技術,并在生產中采用它,同時進行長時間的重構)。
為了管理復雜的狀態,我正在使用 React Context useReducer,這在某種程度上簡化了我的生活,因為它與 Redux 有點相似。
在我的案例中,對于用戶,我有 2 個背景關系:
在我的案例中,我有 2 個背景關系。
- CurrentUserContext OtherUsersContext。
這兩個背景關系都包含了獲取的用戶的敏感和非敏感資料。這里你可能會想:為什么要有userCache?如果這兩個背景關系都可以作為記憶體中的快取來使用的話?
答案是(至少我認為):
沒有辦法在 React 組件或鉤子之外消耗背景關系。它不可能在我的 api 模塊中進行,以便回傳快取資料并避免進行服務器請求。
我在背景關系中保存敏感資料(例如,isFollowed),這取決于當前用戶會話。因此,當用戶注銷時,這些背景關系將被取消掛載(受保護的路徑)。另一方面,我的 usersCache 模塊仍然在那里,沒有敏感資料。
下面是我的 CurrentUserContext 的例子(由于簡單,我在這里沒有使用 reducer,但是在我的 OtherUsersContext 中,由于狀態管理很復雜,我使用了 reducer):
import React, { createContext } from "react"。
import useDidUpdateEffect from "././hooks/useDidUpdateEffect"/span>;
import useStateWithCallback from "././hooks/useStateWithCallback";
import { usersCache } from "././services/firebase/api/users"。
const CurrentUserContext = createContext(null) 。
export default CurrentUserContext;
export function CurrentUserProvider({ children }) {
const [data, setData] = useStateWithCallback(undefined)。
const updateData = (data, merge = true, callback = undefined>) => {
if (merge) {
setData((prevData) => ({ ... prevData, ... data }), callback) 。
} else {
setData(data, callback)。
}
};
useDidUpdateEffect(() => {
console.log(JSON. stringify(data, null, 2))。)
/*
由于當前的用戶資料并不敏感,我們可以在這里
在這里同步用戶快取。
*/
usersCache.updateCachedUser(data.id, data)。
}, [JSON.stringify(data)]); // TODO - 避免不必要的執行 -> deepCompare?
return (
< CurrentUserContext.Provider
value={{}。
data,
setData。
updateData,
}}
>
{children}
</CurrentUserContext.Provider>/span>
);
}
為了避免運行多個useDidUpdateEffects,我正在對用戶資料進行串聯。但是,由于它是復雜的和嵌套的:
userData = {
avatar: {
uri,
thumbnailUri,
},
...
}
當資料沒有變化時,效果會被執行,因為接收到的資料是無序的。
userData = {
avatar: {
thumbnailUri,
uri,
},
...
}
最上層的欄位也不是無序的。
uj5u.com熱心網友回復:
我認為(我可能是錯的),如果你使用這種效果,這整個問題就會消失:
useEffect(() =>/span> {
if(! data) return;
//做一些事情。
},[data])。
uj5u.com熱心網友回復:
我遇到的問題是,我的服務器正在檢索帶有無序欄位的JSON資料...... 所以,你可以嘗試一下目前的兩種解決方案。
@Adam的解決方案是:
@Adam的回答很好,避免了玩自定義鉤子。在其解決方案中,他只是用JSON物件生成一個哈希值,并與前一個哈希值進行比較。如果哈希值相等,那么就不要更新狀態,避免運行useEffect。
但是,這可能會讓你在代碼的不同部分撰寫一些條件并生成哈希值...... 所以,如果你不關心深度比較你的物件,你可以嘗試這個鉤子:
span class="hljs-keyword">import { useRef, useEffect } from "react"。
import { isEqual } from "lodash";
export default function useDeepEffect(
效果。
deps = undefined,
options = { ignoreFirstExecution: false }
) {
const isFirst = useRef(true)。
const prevDeps = useRef(deps);
useEffect(() => {
if (!isFirst.current || !options.ignoreFirstExecution) {
const isSame = prevDeps.current.every((obj, index) => /span>
isEqual(obj, deps[index])
);
if (isFirst.current || !isSame) {
effect()。
}
}
isFirst.current = false;
prevDeps.current = Deps;
}, deps)。
}
如果將選項ignoreFirstExecution設定為 "true",你會得到與使用典型的useDidUpdateEffect相同的行為。
useDeepEffect(
() => {
usersCache.updateCachedUser(data.id, data)。
},
[data],
{ ignoreFirstExecution: true }; [data], { ignoreFirstExecution: true }
);
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/309140.html
標籤:
上一篇:RN:回掃到不同的螢屏
