我有这段代码。
import React, { useState, useEffect } from 'react';
export default function Example() {
const [object, setObject] = useState({
count: 0
});
const onClick = () => {
setObject(old => {
old.count = old.count + 1;
return old;
});
};
return (
<div>
<p>You clicked {object.count} times</p>
<button onClick={e => console.log(object.count)}>Show in log</button>
<button onClick={onClick}>Click me</button>
</div>
);
}
如果单击"单击我",它将增加对象的 count 属性。但由于某些原因,如果单击它,对象仍会更新,但组件不会重新渲染。您可以使用"在日志中显示"按钮检查对象的值。
根据 reactjs.org,每当您设置组件的状态时,它都会重新渲染。但如果你这样写,它就不会了。
但是如果我将 onClick 函数更改为
const onClick = () => {
setObject(oldObject => {
const newObject = { ...oldObject };
newObject.count = oldObject.count + 1;
return newObject;
});
};
然后它将重新渲染组件。
谁能解释一下是什么导致了这种奇怪的行为?
它之所以以这种方式运行,是因为 React 使用了 Object.is 比较算法。
如果你将状态钩子更新为与当前状态相同的值,React 将拯救而不渲染子项或触发效果。
你在第一个代码片段中所做的改变了原始状态——这在 React 世界中几乎总是一个很大的禁忌。React 通常只在某些状态或 prop 发生变化时才重新渲染,并且由于您改变了原始状态,因此看起来状态并没有改变。
在第二个示例中,您将创建原始状态的副本 ( const newObject = {...oldObject}
(。改变副本并返回它很好 - 你没有改变原始状态。
您需要返回对象。 您没有返回正确的对象。尝试这样做:
const onClick = () => {
// setObject({...object, count:object.count+1}); //another way
setObject(old => {
console.log(old)
let updatedCount = old.count + 1
return {...old,count: updatedCount};
});
};
现场示例:https://stackblitz.com/edit/react-sfjzgz
尝试像这样设置object
:
const onClick = () => {
setObject({
count: object.count + 1
});
};
setObject 是一个调度函数。React 以这种方式设计它,你唯一需要提供的是一个新值,这个值被认为是一个改变的状态。
你要做的是,在调度函数中提供一个函数类型,然后改变作为函数参数提供给你的对象。
你做什么
const onClick = () => {
setObject(old => { // <-- a function is provided here
old.count = old.count + 1;
return old;
});
};
你需要做什么
const onClick = () => {
setObject({...object, count: object.count + 1});
// this way no mutation of the original state value is happening,
//and you are guaranteed to have a re-render.
};
请停止调用变量对象和 setObject 我知道这只是一个例子,但发布此代码片段很可能会让您对类型/名称情况感到困惑。