【发布时间】:2020-02-24 13:46:20
【问题描述】:
在以下最小示例中,父组件具有data 属性并将data.value 传递给子组件。我很难理解更新策略到底发生了什么:
const MY_DATAVALUE = {
a: 1,
b: 2
};
const DATA = {
value: MY_DATAVALUE
};
function Child(props) {
useEffect(() => {
console.log("child props changed");
}, [props]);
return <h1>Child</h1>;
}
export default function App() {
const [data, setData] = useState(DATA);
useEffect(() => {
console.log("data changed");
}, [data]);
useEffect(() => {
console.log("data.value changed");
}, [data.value]);
function handleButtonClick() {
const newData = {
value: MY_DATAVALUE
};
setData(newData);
}
return (
<>
<button onClick={handleButtonClick}>Button</button>
<Child value={data.value} />
</>
);
}
(见Codesandbox) 现在,当单击按钮时,我认为会发生以下情况:
App 的
handleButtonClick()被执行,data-state 现在指向一个新对象。因此应用的第一个useEffect(检查data)触发。但是
data.value仍然包含相同的引用(对MY_DATAVALUE),因此App 的第二个useEffect(检查data.value)不会触发。
但是:孩子的useEffect(检查props)触发器。这是为什么?根据家长的说法,data.value 没有改变(否则第二个useEffect 会触发)。
你能解释一下,为什么 Childs useEffect 触发器`?我怎样才能知道道具是否“真的”改变了?我是否必须单独检查所有道具键?
谢谢!
【问题讨论】:
-
我认为这是因为
App组件的状态作为道具传递给Child并且App组件随着状态更新重新渲染,因此孩子们是由于 React 没有对对象内容进行“深度”比较,因此也重新渲染。我认为您需要使用useReducer进行深度状态对象比较。 -
useMemo和useCallback检查道具的差异。任何更改都会触发使用效果,尽管它是相同的数据
标签: javascript reactjs react-hooks use-effect