看起來直接修改反應狀態是一種不好的做法(不要直接修改狀態),原因已經在 SO(見問題)和網路外部(見博客文章)上多次討論過。
問題似乎是,當直接修改狀態時,對當前虛擬DOM中的狀態進行了更改。因此,當需要重新渲染時,新虛擬 DOM 中的狀態將與前一個虛擬 DOM 中的狀態相同,并且不會更新實際 DOM。
但是如果你不想在修改狀態時觸發重新渲染呢?這種情況下直接修改狀態應該是安全的吧?
下面描述了我所面臨的情況,這使我陷入了評估在某些情況下是否可以安全地直接修改狀態的兔子洞。
我有一個useReducer由具有許多鍵的物件組成的反應狀態。
const initialState = {
a: 0,
b: 1,
c: 2,
d: 3,
};
在狀態減速器中,我并不總是回傳一個新狀態。說如果我想修改a或者b我也想觸發重新渲染,但是如果我修改c或者d我不想要,因為 DOM 無論如何都不會受到影響。
我認為candd是一種refs:它們在單個渲染中是可變的,但它們的值在重新渲染之間保留。
當然,我可以將狀態限制為僅aand并為每個andb創建一個參考,但它們都是相關的,我經常需要將它們一起傳遞給一個函式。因此,在我的情況下,將裁判保持在狀態會更好。
下面是減速器的樣子:cd
// When modifying `a` or `b` `action.modifyRef` is set to `false`.
// When modifying `c` or `d` `action.modifyRef` is set to `true`.
const reducer = (state, action) => {
if (action.modifyRef) {
state[action.key] = action.value;
return state;
}
const newState = {
...state,
[action.key]: action.value,
};
return newState;
};
如果一開始不需要重新渲染,我是否可以相信我可以安全地修改狀態而不觸發重新渲染?
如果上一個問題的答案是“是”,那么修改c或者d我可以直接修改狀態而不是對減速器發送動作,不是嗎?
state.c = 5;
// the above statement is equivalent to the one below
dispatchState({ modifyRef: true, key: 'c', value: 5 });
uj5u.com熱心網友回復:
我不認為你c所d描述的(不應該導致重新渲染的成員,并且不用于渲染的成員)是狀態資訊,因為該術語在 React 中使用。它們是實體資訊。在函陣列件中使用非狀態實體資訊的常規方法是使用 ref。
在務實的位和位元組級別上,您可以在狀態中保存非狀態資訊并直接修改它而不是使用狀態設定器(直接或間接)?是的,你可能可以,至少最初是這樣。我可以看到導致應用程式/頁面的不正確行為的唯一情況涉及渲染,并且您已經說過它們不用于此。
但如果你這樣做:
- 這會讓其他團隊成員(或者您自己,如果您必須在休息后回傳代碼)感到困惑。語意很重要。如果你稱它為狀態,但它不是狀態,那會讓人絆倒。這就像呼叫一個不是函式的函式:在某些時候,有人會嘗試呼叫那個“函式”。
- 這將是一個維護風險,因為團隊成員(或您自己在休息后)可能會進行無害的更改,以便
c或d用于渲染(因為畢竟它們處于狀態,所以可以將它們用于渲染),也許通過將其中一個作為道具傳遞給子組件。然后,您會遇到應用程式在更改時無法正確重新呈現的情況。
有點切線,但在對您提到的問題的評論中,您“......它們都是相關的,我經常需要將它們一起傳遞給一個函式......”
使用 ref 來保存cand d,設定可能如下所示:
const [{a, b}, dispatch] = useReducer(/*...*/);
const instanceRef = useRef(null);
const {c, d} = instanceRef.current = instanceRef.current ?? {c: /*...*/, d: /*...*/};
然后獲取一個物件以將它們視為一個單元是:
const stuff = {a, b, c, d};
// ...use `stuff` where needed...
在現代 JavaScript 引擎中創建物件非常昂貴,因為這是他們積極優化的常見操作。:-)
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/463270.html
標籤:javascript 反应 反应钩子 反应状态
上一篇:洗掉陣列A中存在于陣列B中的所有元素,而不使用雙回圈
下一篇:遞回獲取狀態等于一的嵌套陣列
