React Native Component 生命周期
简介
就像 Android 开发中的 View 一样,React Native(RN) 中的组件也有生命周期(Lifecycle)。所谓生命周期,就是一个对象从开始生成到最后消亡所经历的状态。RN 组件的生命周期整理如下图:
Default Porps
在自定义Component中,可通过defaultProps指定默认的属性。
// MyComponent.js
MyComponent.defaultProps = { name: 'unknown' }
以下用法的区别:
1)<MyComponent name={null} />
2)<MyComponent name={undefined} />
如果给name传入的值是null,那么最终页面上的输出是空,null会生效;如果传入的是undefined,那么React认为这个值没有定义,则会使用默认值,最终在页面上的显示unknown。
componentWillMount()
componentWillMount函数在第一次render之前被调用,并且只会被调用一次。当组件进入到这个生命周期中时,所有的state和props已经配置完毕,我们可以通过this.props和this.state访问它们,也可以通过setState重新设置状态。总之推荐在这个生命周期函数里进行状态初始化的处理,为下一步render做准备。
render()
- 不可以在render中setState,避免死循环
- 不可以在render中通过ReactDOM.findDOMNode方法访问原生的DOM元素,存在如下两个风险:
1)此时虚拟元素还没有被渲染到页面上,所以你访问的元素并不存在
2)因为当前的render即将执行完毕返回新的DOM结构,你访问到的可能是旧的数据。
componentDidMount()
出生阶段时componentWillMount和render的调用顺序是
A -> A.0 -> A.0.0 -> A.0.1 -> A.1 -> A.2.
componentDidMount调用顺序是
A.2 -> A.1 -> A.0.1 -> A.0.0 -> A.0 -> A
componentWillReceiveProps(nextProps)
当传递给组件的props发生改变时,组件的componentWillReceiveProps即会被触发调用。虽然props的更改会引起componentWillReceiveProps的调用;但componentWillReceiveProps的调用并不意味着props真的发生了变化。
//MyComponent.js
export default class MyComponent extends Component {
constructor(props){
super(props);
this.state = {
count:0,
};
}
render() {
return (
<TouchableOpacity onPress={()=>{this.setState({count:2})}}>
<MyBtn count={this.state.count}/>
</TouchableOpacity>
);
}
}
//MyBtn.js
export default class MyBtn extends Component {
componentWillReceiveProps(nextProps) {
alert(nextProps.count)
}
render() {
return (
<View style={{flexDirection:'row'}}>
<Text>{this.props.count}</Text>
</View>
);
}
}
每次点击count的值都设置2,值不变的情况下,componentWillReceiveProps依然会调用。而为什么React不尝试去做一个是否相等的判断呢?
因为新传入的属性和旧属性可能引用的是同一块内存区域(引用类型),所以单纯的用===判断是否相等并不准确。可行的解决办法之一就是对数据进行深度拷贝然后进行比较,但是这对大型数据结构来说性能太差,还能会碰上循环引用的问题。
shouldComponentUpdate()
可以通过shouldComponentUpdate的返回值来控制是否要执行render,避免无效的render引起的性能问题。
当count为偶数时不显示,示例如下:
export default class TestComponent extends Component {
constructor(props){
super(props);
this.state = {
count:0,
};
}
shouldComponentUpdate(nextProps, nextState) {
if (nextState.count % 2 == 0) {
return false
}
return true
}
render() {
return (
<TouchableOpacity onPress={()=>{
let count = this.state.count
this.setState({count:count+1})
}}>
<MyBtn count={this.state.count}/>
</TouchableOpacity>
);
}
}