React 中父组件给子组件传值
在 React 前端框架开发过程中,父组件和子组件之间相互传输数据等操作是基本的开发知识。但是在使用过程中,难免会有一些意想不到的Bug。
这里就记录了一个踩坑经历,表现的现象为父组件给子组件传输新的数据,但是数据没有在组件中生效。
一、问题说明
父组件更新子组件的props,在子组件接收到新的props时,需要更新子组件的state,但是却没有重新渲染。我想在 componentWillReceiveProps方法
中更新子组件的state,但是却没有重新渲染。
官网上有这么一句话:
在该函数中调用 this.setState() 将不会引起第二次渲染。
如果不重新渲染,那么获取到的新数据怎么更新到视图上去?
二、子组件显示父组件传过来的 props 的两种方法
2.1、直接使用
这种方式,父组件改变props后,子组件重新渲染,由于直接使用的props,所以我们不需要做什么就可以正常显示最新的props。
class Child extends Component {
render() {
return <div>{this.props.someThings}</div>
}
}
2.2、子组件将 props 转化为子组件的 state
由于会将父组件传输过来的数据,转化到子组件的 state 数据中;所以需要使用 componentWillReceiveProps
生命周期函数。
子组件接受新的 props 数据,并转化到子组件的 state 数据中的过程:
- 子组件接受到新的 props 数据后,会重新渲染一次子组件。除非你做了处理来阻止(比如使用:
shouldComponentUpdate
)。 - 子组件设置 state 数据时,会重新渲染一次子组件。
- 按照上述过程,子组件会被渲染两次,这样会造成性能浪费;所以
componentWillReceiveProps
函数优化为不引起第二次渲染。
class Child extends Component {
constructor(props) {
super(props);
this.state = {
someThings: props.someThings
};
}
componentWillReceiveProps(nextProps) {
this.setState({someThings: nextProps.someThings});
}
render() {
return <div>{this.state.someThings}</div>
}
}
三、说明补充
3.1、摘录一
这里说的不会造成第二次的渲染,并不是说这里的setState不会生效。
在这个方法里调用 setState 会在组件更新完成之后在 render 方法执行之前更新状态,将两次的渲染合并在一起。
可以在 componentWillReceiveProps
执行 setState
,但是如果你想在这个方法里获取 this.state
得到的将会是上一次的状态。
3.2、摘录二
永远不要在 constructor
里使用 props
初始化state
值,不然就会导致这个问题。
要么直接用props渲染,要么使用新的生命周期函数。
class Child extends Component {
state = { text: '' };
//getDerivedStateFromProps is invoked right before calling the render method, both on the initial mount and on subsequent updates.
//It should return an object to update the state, or null to update nothing.
//getDerivedStateFromProps在调用render方法之前被调用,无论是在初始装载还是在随后的更新中。
//它应该返回一个对象来更新状态,或者返回null来不更新任何内容。
static getDerivedStateFromProps(props) {
return {
text: props.text
};
}
render() {
return <p>{this.state.text}</p>
}
}
class Parent extends Component {
state = {
name: 'xxx'
}
render() {
return (
<div>
<Child text={this.state.name}/>
<button onClick={() => this.setState({name: 'zzz'})}>change</button>
</div>
)
}
}