深入研究后,我以为我理解了组件的props不能由组件本身更新,尽管可以由父组件更改。
但是我在react docs中找到了这一部分:
React可以将多个setState()调用批处理为一个更新,以提高性能。 由于this.props和this.state可以异步更新,因此您不应依赖于它们的值来计算下一个状态。
因此,我试图以我所理解的来解释此摘录所说的内容。如果道具已更新,则更新必须来自父组件。如果更新来自父组件,为什么它可能是异步的?
答案 0 :(得分:0)
请检查zloctb here给出的答案
// assuming this.state.count === 0
this.setState({count: this.state.count + 1});
this.setState({count: this.state.count + 1});
this.setState({count: this.state.count + 1});
// this.state.count === 1, not 3
Solution
this.setState((prevState, props) => ({
count: prevState.count + props.increment
}));
答案 1 :(得分:0)
如果道具已更新,则更新必须来自父组件。
是的。
如果更新来自父组件,为什么它可能是异步的?
您可以将带有道具的父母的setState()
传递给孩子,并在孩子的代码中的某个地方调用它。而且它仍然可能是异步的。我想出了以下示例:
class Container extends React.Component {
state = { containerState: 0 };
render() {
return (
<Component
containerState={this.state.containerState}
setContainerState={this.setState.bind(this)}
/>
);
}
}
然后,在子Component
中,您具有如下代码:
this.props.setContainerState({
containerState: this.props.containerState + 1
});
// You want to use updated this.props.containerState here, but you can't,
// because parent's setState() MAY BE deferred
this.props.setState({ componentStateUpdatedWithObject: this.props.containerState });
// Now if you use the function instead, you can expect to get updated props
// as a second argument
this.props.setState((state, props) => ({
componentStateUpdatedWithFunction: props.containerState
}));
查看示例的完整代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<div id="root"></div>
</body>
<script
src="https://unpkg.com/react@16/umd/react.development.js"
crossorigin
></script>
<script
src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"
crossorigin
></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script type="text/babel">
class Container extends React.Component {
state = { containerState: 0 };
render() {
return (
<Component
containerState={this.state.containerState}
setContainerState={this.setState.bind(this)}
/>
);
}
}
class Component extends React.Component {
state = {
componentStateUpdatedWithObject: [0, this.props.containerState],
componentStateUpdatedWithFunction: [0, this.props.containerState]
};
log = title => {
console.log(title);
console.log("- containerState", this.props.containerState);
console.log(
"- componentStateUpdatedWithObject",
this.state.componentStateUpdatedWithObject
);
console.log(
"- componentStateUpdatedWithFunction",
this.state.componentStateUpdatedWithFunction
);
console.log("==========");
};
update = () => {
this.log("before update");
this.props.setContainerState({
containerState: this.props.containerState + 1
});
this.log("after setContainerState");
this.setState({
componentStateUpdatedWithObject: [
this.state.componentStateUpdatedWithObject[0] + 1,
this.props.containerState
]
});
this.log("after setState with object");
this.setState((state, props) => ({
componentStateUpdatedWithFunction: [
state.componentStateUpdatedWithFunction[0] + 1,
props.containerState
]
}));
this.log("after setState with function");
};
componentDidMount() {
// setInterval(this.update, 2000);
}
render() {
this.log("on render");
console.log("---------------------------------------------");
return (
<div>
<div>containerState: {this.props.containerState}</div>
<div>
componentStateUpdatedWithObject:{" "}
{this.state.componentStateUpdatedWithObject.join(", ")}
</div>
<div>
componentStateUpdatedWithFunction:{" "}
{this.state.componentStateUpdatedWithFunction.join(", ")}
</div>
<button onClick={this.update}>UPDATE</button>
</div>
);
}
}
ReactDOM.render(<Container />, document.getElementById("root"));
</script>
</html>
注意:并非所有setState()
调用都是异步的。在我的示例中,如果您在setInterval(this.update, 2000)
中取消对componentDidMount
的注释,您将不会得到相同的行为。这样setState()
调用是同步的。
请参见以下链接以说明发生这种情况的原因:When and why are setState() calls batched?
简而言之,这是因为
当前(React 16和更早版本),默认情况下仅批处理React事件处理程序中的更新。有一种不稳定的API可以在极少数情况下在需要时强制在事件处理程序之外进行批处理。