在这个例子中
https://codepen.io/ismail-codar/pen/QrXJgE?editors=1011
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
static getDerivedStateFromProps(nextProps, prevState) {
console.log("nextProps", nextProps, "\nprevState", prevState)
if(nextProps.count !== prevState.count)
return {count: nextProps.count};
else
return null;
}
handleIncrease(e) {
this.setState({count: this.state.count + 1})
}
handleDecrease(e) {
this.setState({count: this.state.count - 1})
}
render() {
return <div>
<button onClick={this.handleIncrease.bind(this)}>+</button>
{this.state.count}
<button onClick={this.handleDecrease.bind(this)}>-</button>
</div>;
}
}
class Main extends React.Component {
constructor(props) {
super(props);
this.state = { initialCount: 1 };
}
handleChange(e) {
this.setState({initialCount: e.target.value})
}
render() {
return <div>
<Counter count={this.state.initialCount} />
<hr/>
Change initial:<input type="number" onChange={this.handleChange.bind(this)} value={this.state.initialCount} />
</div>
}
}
ReactDOM.render(
<Main/>,
document.getElementById("root")
);
预期: 单击+ / - 按钮和文本框更改必须是更新计数
目前: 主组件将initialCount存储在自己的状态,并将初始计数传递给子计数器组件。
如果从textbox触发handleChange并且更新了initialCount,则子计数器组件也会正确更新,因为getDerivedStateFromProps静态方法提供了这个。
但是改变计数器组件中的计数值,通过handleIncrease和handleDecrease方法更新本地状态就可以了。
问题是getDerivedStateFromProps重新触发此次并重置计数值。但我没想到这是因为Counter组件本地状态更新父主组件没有更新。 UNSAFE_componentWillReceiveProps正在以这种方式工作。
摘要我的getDerivedStateFromProps用法不正确,或者我的方案有另一种解决方案。
此版本https://codepen.io/ismail-codar/pen/gzVZqm?editors=1011适用于componentWillReceiveProps
答案 0 :(得分:6)
尝试&#34;同步&#34;像你这样的道具状态极易出错,导致错误的应用程序。
事实上即使你的example with componentWillReceiveProps
也有错误。
如果您更频繁地重新渲染父组件,则会丢失用户输入。
这是demo of the bug。
增量计数器,然后单击“演示bug”,它将吹走计数器。但是那个按钮的setState
应该是完全不相关的。
这显示为什么尝试将状态同步到道具是一个坏主意,应该避免。
相反,请尝试以下方法之一:
您可以完全控制您的组件&#34;通过父道具并删除当地的州。
或者,您可以使您的组件完全“不受控制”,并在必要时通过为孩子提供不同的key
来重置父级的子状态。
这两种方法都在 this article on the React blog about avoiding deriving state 中描述。博客文章包含演示的详细示例,因此我强烈建议您查看它。
答案 1 :(得分:1)
我不确定我是否理解正确,但是如果你想将道具用作种子&#34;对于在构造函数中执行此操作的初始值,您甚至不需要getDerivedStateFromProps
。你实际上不需要复制州:
class Counter extends React.Component {
render() {
return <div>
<button onClick={this.props.handleIncrease}>+</button>
{this.props.count}
<button onClick={this.props.handleDecrease}>-</button>
</div>;
}
}
class Main extends React.Component {
constructor(props) {
super(props);
this.state = { count: 1 };
}
handleIncrease() {
this.setState(prevState => ({count: prevState.count + 1}))
}
handleDecrease() {
this.setState(prevState => ({count: prevState.count - 1}))
}
render() {
return (
<div>
<Counter count={this.state.count} />
<hr/>
Change initial:
<input
type="number"
handleIncrease={this.handleIncrease.bind(this)}
handleDecrease={this.handleDecrease.bind(this)}
count={this.state.count}
/>
</div>
)
}
}