2 回答

TA贡献1993条经验 获得超5个赞
经过几个小时的修补并再次阅读反应文档后,我终于可以回答我自己的问题了。简而言之,问题在于商店中的状态并不是一成不变地更新的。
Redux 是 Flux 架构的实现,在其文档中说得非常清楚:
Redux 期望所有状态更新都是不可变地完成
因此,上面代码中的罪魁祸首就在addNowstore的函数中。该Array.push()方法通过附加一个项目来改变现有数组。执行此操作的不可变方法是使用该Array.concat()方法或 ES6 扩展语法(解构)[...this.values],然后将新数组分配给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中的函数更改useEffect为以下内容:
setValues((prev) => {
const newValue = store.getAll()
console.log("Previous:", prev)
console.log("New value:", newValue)
return newValue
})
在控制台中,很明显,当存储中的状态可变地更改时,单击第一个按钮后,先前的状态和新的状态将始终相同并引用相同的数组。但是,当存储中的状态不可改变地更改时,先前的状态和新的状态不会引用相同的数组。此外,在控制台中可以清楚地看到先前的状态数组比新的状态数组少一个值。
为什么使用类组件时状态更改会触发重新渲染,而使用钩子时则不会?
根据类组件的 setState 函数的React 文档。
setState() 总是会导致重新渲染,除非 shouldComponentUpdate() 返回 false。
这意味着无论存储中的状态是可变的还是不可变的,当触发更改事件并setState调用该函数时,React 都会重新渲染组件并显示“新”状态。然而,钩子的情况并非如此useState。
根据useState hook的 React 文档:
如果将 State Hook 更新为与当前状态相同的值,React 将退出而不渲染子项或触发效果。(React 使用 Object.is 比较算法。)
这意味着当通过改变原始对象来完成对存储中数组的更改时,react 在决定再次渲染之前会检查新状态和先前状态是否相同。由于先前状态和当前状态的引用是相同的,因此 React 不执行任何操作。为了解决这个问题,商店中的更改必须一成不变地完成。

TA贡献1900条经验 获得超5个赞
useEffct 监听值的变化,但 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>
);
}
添加回答
举报