2 回答

TA貢獻1993條經(jīng)驗 獲得超6個贊
經(jīng)過幾個小時的修補并再次閱讀反應(yīng)文檔后,我終于可以回答我自己的問題了。簡而言之,問題在于商店中的狀態(tài)并不是一成不變地更新的。
Redux 是 Flux 架構(gòu)的實現(xiàn),在其文檔中說得非常清楚:
Redux 期望所有狀態(tài)更新都是不可變地完成
因此,上面代碼中的罪魁禍首就在addNowstore的函數(shù)中。該Array.push()方法通過附加一個項目來改變現(xiàn)有數(shù)組。執(zhí)行此操作的不可變方法是使用該Array.concat()方法或 ES6 擴展語法(解構(gòu))[...this.values],然后將新數(shù)組分配給this.values.
addNow() {
this.values.push(Date.now()); // Problem - Mutable Change
this.values = this.values.concat(Date.now()) // Option 1 - Immutable Change
this.values = [...this.values, Date.now()] // Option 2 - Immutable Change
this.emit('change')
}
要查看 React 組件中每個更改的效果,請將鉤子setValues中的函數(shù)更改useEffect為以下內(nèi)容:
setValues((prev) => {
const newValue = store.getAll()
console.log("Previous:", prev)
console.log("New value:", newValue)
return newValue
})
在控制臺中,很明顯,當存儲中的狀態(tài)可變地更改時,單擊第一個按鈕后,先前的狀態(tài)和新的狀態(tài)將始終相同并引用相同的數(shù)組。但是,當存儲中的狀態(tài)不可改變地更改時,先前的狀態(tài)和新的狀態(tài)不會引用相同的數(shù)組。此外,在控制臺中可以清楚地看到先前的狀態(tài)數(shù)組比新的狀態(tài)數(shù)組少一個值。
為什么使用類組件時狀態(tài)更改會觸發(fā)重新渲染,而使用鉤子時則不會?
根據(jù)類組件的 setState 函數(shù)的React 文檔。
setState() 總是會導(dǎo)致重新渲染,除非 shouldComponentUpdate() 返回 false。
這意味著無論存儲中的狀態(tài)是可變的還是不可變的,當觸發(fā)更改事件并setState調(diào)用該函數(shù)時,React 都會重新渲染組件并顯示“新”狀態(tài)。然而,鉤子的情況并非如此useState。
根據(jù)useState hook的 React 文檔:
如果將 State Hook 更新為與當前狀態(tài)相同的值,React 將退出而不渲染子項或觸發(fā)效果。(React 使用 Object.is 比較算法。)
這意味著當通過改變原始對象來完成對存儲中數(shù)組的更改時,react 在決定再次渲染之前會檢查新狀態(tài)和先前狀態(tài)是否相同。由于先前狀態(tài)和當前狀態(tài)的引用是相同的,因此 React 不執(zhí)行任何操作。為了解決這個問題,商店中的更改必須一成不變地完成。

TA貢獻1900條經(jīng)驗 獲得超5個贊
useEffct 監(jiān)聽值的變化,但 setValues 只存在于 useEffect 中,我認為你根本不需要 useEffect
你可以嘗試這樣的事情:
// App.js
import store from './store';
function App() {
const [values, setValues] = useState([]);
const onChangeHandler = () => {
console.log("Change called");
const storeValues = store.getAll();
setValues(storeValues);
};
const handleClick = () => {
store.addNow();
onChangeHandler();
};
return (
<div>
<button onClick={handleClick}>Click to add</button>
<ul>
{values.map(val => <li key={val}>{val}</li>)}
</ul>
</div>
);
}
添加回答
舉報