假设您希望某个子组件在init(而不是在用户输入时(设置父组件的状态。在下面的示例中,如果有多个组件更改同一父级,则某些子级所做的更改将丢失!
对父级执行并发更改的正确方法是什么?
import { useEffect, useState } from 'react';
function Child({letter,parentState,setParentState}) {
const [value,setValue] = useState("hello");
useEffect(()=>{
const new_parent_state={
...parentState,
[letter]: "hello"
}
setParentState(new_parent_state);
},[value]);
return <div>hello {letter}</div>
}
function App() {
const [parentState,setParentState] = useState({"A": null, "B": null})
useEffect(()=>{
console.log(parentState);
});
return (
<div className="App">
<Child key="A" letter="A" parentState={parentState} setParentState={setParentState}></Child>
<Child key="B" letter="B" parentState={parentState} setParentState={setParentState}></Child>
</div>
);
}
export default App;
预期输出为
{
"A":"hello",
"B": "hello"
}
实际输出为
{
"A": null,
"B": "hello"
}
组件A:
parentState={"A": null, "B": null}
。A将状态更新为:{"A": "hello", "B": null}
组件B:
parentState={"A": null, "B": null}
。B将状态更新为:{"A": null, "B": "hello"}
如果交换DOM树中A和B组件的顺序,您将看到其他输出。
您看到的问题的原因是提供给单个组件的parentState
已过时。您需要使用setter回调使其按预期工作(始终获得更新状态(。
代替:
const new_parent_state={
...parentState,
[letter]: "hello"
}
setParentState(new_parent_state);
用途:
setParentState((prevParentState) => ({
...prevParentState,
[letter]: "hello"
}));
工作演示:
function Child({ letter, parentState, setParentState }) {
const [value, setValue] = React.useState("hello");
React.useEffect(() => {
setParentState((prevParentState) => ({
...prevParentState,
[letter]: "hello"
}));
}, [value]);
return <div>hello {letter}</div>;
}
function App() {
const [parentState, setParentState] = React.useState({ A: null, B: null });
React.useEffect(() => {
console.log(parentState);
});
return (
<div className="App">
<Child
key="A"
letter="A"
parentState={parentState}
setParentState={setParentState}
></Child>
<Child
key="B"
letter="B"
parentState={parentState}
setParentState={setParentState}
></Child>
</div>
);
}
ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div class='react'></div>
旁注:您可能期望在这里有三个日志。但React已经智能地将两个状态更新分批为一个更新。