13.react生命周期
教程1-14完整项目地址 https://github.com/x1141300029/react-Todos.git
问题:以当前代码,在src/components/TodoList/TodoItem/index.js
中的render
函数如果添加一行输出的话
1.页面加载的时候回输出两次(没有问题)
2.点击复选框又会输出两次(有问题,应该输出一次,而不是多次)
解释:点击复选框又输出两次,是因为组件进行了重新渲染
1.在src/components/TodoItem/index.js
中添加生命周期函数
判断下一次的props和上一次的props是否是一样的,如果一样则不进行更新,
shouldComponentUpdate() return false
即可
/**
* 是否需要更新组件
* @param nextProps
* @param nextState
* @param nextContext
* @return boolean true更新 false不更新
*/
shouldComponentUpdate(nextProps, nextState, nextContext) {
// console.log("-------shouldComponentUpdate-------");
// console.log(this.props)
// console.log(nextProps)
// console.log("-------shouldComponentUpdate-------");
//如果两个值不相同的情况下才进行页面渲染
return nextProps.isCompleted!==this.props.isCompleted;
// return true;
}
前后值相比较也可以使用框架进行比较 lodashjs
lodash.isEqual
使用的是深度比较(递归)比较消耗性能
2.第三种比较方式 src/components/TodoItem/index.js
取消继承`Component`,继承于`PureComponent`
去除生命周期`shouldComponentUpdate`也可以进行比较
这种继承方式属于浅比较
- React组件生命周期分为三个部分(挂载、更新、卸载)
3.1. 挂载卸载过程
3.1.1.constructor()
1.`constructor()`中完成React数据的初始化
2.`constructor(props,context)`接收两个参数:`props`和`context`
3.如果在函数内部使用这两个参数时,需要使用`super()`传入这两个参数
注意:只要使用了constructor()就必须写super()否则会导致this指向错误
3.1.2. componentWillMount()
`componentWillMount()`一般使用的比较少,它更多是在服务器端渲染时使用。
它代表的过程是组件经历了`constructor()`初始化数据后,但是还未渲染`DOM`时。
3.1.3. componentDidMount()
组件第一次渲染完成,此时dom节点已经生成,可以在这里调用ajax请求,返回数据setState后组件会重新渲染
3.2.4. componentWillUnmount()
在此处完成组件的卸载和数据的销毁
1. clear你在组件中所有的setTimeout,setInterval
2. 移出所有组件中的监听removeEventListener
3. 有时候我们会碰到这个
> Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please
> check the code for the undefined component.
原因:因为你再组件中的ajax请求返回setState,而你组件销毁的时候,请求还没有完成,所以会报warning
解决办法:
componentDidMount(){
this.isMount=true;
axios.post().then(res)=>{
this.isMount&&this.setState({//增加条件ismount为true事才进行 setState
aaa:res
})
}
}
componentWillUnmount(){
this.isMount===false
}
- 更新过程
4.1.componentWillReceiveProps(nextProps)
4.1.1. 在接收父组件改变后的props
需要重新渲染组件的时候用的比较多
4.1.2. 接收一个参数nextProps
4.1.3. 通过对比nextProps
和this.props
,将nextProps
的state
为当前组件的v
,从而重新渲染组件
componentWillReceiveProps(nextProps){
nextProps.openNotice!==this.props.openNotice&&this.setState({
openNotice:nextProps.openNotice
},()=>{
console.log(this.state.openNotice:nextProps);
//将state更新为nextProps
})
}
4.2. shouldComponentUpdate(nextProps,nextState)
4.2.1. 主要用于性能优化(部分更新)
4.2.2. 唯一用于控制组件重新渲染的生命周期,由于在react
中,setState
以后,state
发生变化,组件会进入重新渲染的流程,在这里return false
可以组织组件的更新
4.2.3. 因为react
父组件的重新渲染会导致其子组件的重新渲染,这个时候其实我们是不需要所有子组件都跟着渲染的,因此需要在子组件的该声明周期中做出判断
4.3. componentWillUpdate(nextProps,nextState)
showldComponentUpdate
返回true
以后,组件进入重新渲染的流程,进入componentWillUpdate
这样同样可以拿到nextProps
和nextState
4.4. componentDidUpdate(prevProps,prevState)
组件更新完毕后,react
置灰在第一次初始化成功后进入componentDidmount
,之后每次重新渲染都会进入这个生命周期,这里可以拿到prevProps
和prevState
即更新前的props
和state
4.5. render()
render
函数会插入jsx
生成的dom
结构,react
会生成一份虚拟dom
树,在每一次组件更新时,在此react
会通过其diff
算法比较更新前后的新旧DOM
树,比较以后,找到最小的有差异的DOM
节点,并重新渲染
5.React
新增的生命周期
5.1. getDerivedStateFromProps(nextProps,prevState)
代理
componentWillReceiveProps()
老版本中componentWillReceiveProps()
方法判断前后两个props是否相同,如果不同再进行新的props
更新到响应的state
上去。这样做以来回破坏state
数据的单一数据源,导致组件状态变得不可预测,另一方面也会增加组件的重新绘制次数
例如:
//before
componentWillReceiveProps(nextProps){
if(nextProps.isLogin!==this.props.isLogin){
this.setState({
isLogin:nextProps.isLogin
})
}
if(nextProps.isLogin){
this.handleClose();
}
}
//after
static getDerivedStateFromProps(nextProps,prevState){
if(nextProps.isLogin!==prevState.isLogin){
return {
isLogin:nextProps.isLogin
}
}
return null;
}
componentDidUpdate(prevProps,prevState){
if(!prevState.isLogin&&this.props.isLogin){
this.handleClose();
}
}
两者最大的不同就是:
在
componentWillReceiveProps
中,我们一般会做以下两件事,一是根据props
来更新state
,二是触发一些回调,例如:动画或页面跳转等。
1.在老版的`react`中,这两件事我们都需要在`componentWillReceiveProps`中去做
2.而在新版中,官方将更新`state`与触发回调更新分配到了`getDerivedStateFromProps`与`componentDidUpdate`中,是的组件整体的更新逻辑更为清晰,而且在`getDerivedStateFromProps`中还禁止了组件去访问`this.props`强制让开发者去比较nextProps与prevState中的值,以确保当开发者用到`getDerivedStateFromProps`这个生命周期函数时,就是在根据当前的`props`来更新组件的`state`,而不是去做其他一些让组件自身状态变得更加不可以预测的事情
5.2.getSnapshotBeforUpdate(prevProps,prevState)
代替
componentWillUpdate
常见的componentWillUpdate
的用例是在组件更新前,读取当前某个DOM
元素的状态,并在componentDidUpdate
中进行相应处理
区别:
5.2.1. 在React开启一步渲染模式后,在render阶段读取到的DOM元素状态并不总是和commit
阶段相同,这就导致在componentDidUpdate
中使用componentWillUpdate
中读取到的DOM
元素状态是不安全的,因为这时的值很可能已经失效了
5.2.2.getSnapshoBeforUpdate
会在最终的render
之前被调用,也就是说在getSnapshotBeforeUpdate
中读取到的DOM
元素状态是可以保证与componentDidUpdate
中一致的
此生命周期返回的任何职都将作为参数传递给componentDidUpdate()