import { render } from 'react-dom'
import React from 'react'
class Child extends React.Component {
constructor(props) {
super(props)
this.state = {
list: props.list
}
}
handleCilck = () => {
this.setState({
list: this.state.list.concat({ name: '小明' })
})
}
render() {
return (
<div>
<button onClick={this.handleCilck}>添加</button>
{this.state.list.map((item, index) => {
return <h1 key={index}>Hello, {item.name}</h1>
})}
</div>
)
}
}
class Parent extends React.Component {
constructor(props) {
super(props)
this.state = {
list: [{ name: '小红' }, { name: '小兰' }]
}
}
handleClick = () => {
this.setState({
this.setState({list: [{name: '小绿'}]})
})
}
render() {
return (
<div>
<button onClick={this.handleClick}>点击更新props</button>;
<Child list={this.state.list} />;
</div>
)
}
}
export default Parent;
我们想得到的结果是子组件根据父组件传的props值的改变来渲染内容,但是结果显示子组件渲染的列表并不会跟随父组件更新。
子组件会执行render,但是渲染出来的列表数据不变。
**原因:**父组件更新导致子组件更新时,子组件的生命周期执行顺序如下:
也就是说子组件刷新的时候,不再执行constructor,当然也就不会对state重新赋值,所以子组件虽然执行了render,但是渲染数据不变。
解决方案:
1、在componentWillReceiveProps中重新对state赋值。
componentWillReceiveProps在初始化render的时候不会执行,它会在Component接受到新的状态(Props)时被触发,一般用于父组件状态更新时子组件的重新渲染。
componentWillReceiveProps中想作任何变更最好都将两个状态进行比较,假如状态有异才执行下一步。不然容易造成组件的多次渲染,并且这些渲染都是没有意义的。
componentWillReceiveProps(nextProps) {
if(nextProps.list !== this.props.list){
this.setState({
list: nextProps.list
})
}
}
2、使用getDerivedStateFromProps
这个生命周期函数是为了替代componentWillReceiveProps存在的,所以在你需要使用componentWillReceiveProps的时候,就可以考虑使用getDerivedStateFromProps来进行替代了。
getDerivedStateFromProps是一个静态函数,也就是这个函数不能通过this访问到class的属性,也并不推荐直接访问属性。而是应该通过参数提供的nextProps以及prevState来进行判断,根据新传入的props来映射到state。
需要注意的是,如果props传入的内容不需要影响到你的state,那么就需要返回一个null,这个返回值是必须的,所以尽量将其写到函数的末尾。
static getDerivedStateFromProps(nextProps){
// 当传入的list 发生变化的时候,更新state
if(nextProps.list !== this.props.list){
this.setState({
list: nextProps.list
})
}
// 否则,对于state不进行任何操作
return null
}
参考链接:
https://zhuanlan.zhihu.com/p/83623692
https://juejin.im/post/5cf0e961f265da1b8e7085e6