原因
一个派生 state 值[num]也被 setState 方法更新时,这个值就不是一个单一来源的值了。
误解
getDerivedStateFromProps 和 componentWillReceiveProps 只会在 props “改变”时才会调用。实际上只要父级重新渲染时,这两个生命周期函数就会重新调用,不管 props 有没有“变化”。
在这两个方法内直接复制props 到 state 是不安全的。这样做会导致 state 后没有正确渲染。
demo 示例
- 如下代码,可以自己本地跑一遍,无论怎么点击按钮,数字一直是1,setState并未生效
class Children extends React.Component {
constructor(props) {
super(props)
this.state = {
num: props.num
}
}
handleClick = () => {
this.setState({
num: this.state.num+1 });
};
componentWillReceiveProps(nextProps) {
// This will erase local state updates!
this.setState({
num: nextProps.num }); }
}
render() {
return (
<div>
<input type='button' value='点击+1' onClick={
this.handleClick} />
<span>{
this.state.num}</span>
</div>
)
}
}
class Fa extends React.Component {
constructor(props) {
super(props)
this.state = {
count: 0
}
}
componentDidMount() {
this.interval = setInterval(
() =>
this.setState(prevState => ({
count: prevState.count + 1
})),
1000
);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
return (
<Fragment>
<Children num={
1} />
</Fragment>
);
}
}
一般派生状态的bug不外乎如下两种情况
- 直接复制 props 到 state 上;
- 如果 props 和 state 不一致就更新 state