一. 老生命周期
<1> 初始化阶段
(1) componentWillMount()
这个生命周期已经不推荐使用了,因为在 react 近期的版本中,为了优化 DOM diff 渲染算法
,采用了 fiber
技术,该技术核心思想是把DOM diff 渲染算法
划分成一个一个小任务,并且每个任务都有优先级高低,比如,马上要render()展示的组件的优先级就高,所以就会先执行该部分代码,由于 componentWillMount 是马上要挂载,但还没挂载,所以优先级就低,所以就会被优先级高的任务抢断,就可能会导致 componentWillMount() 被执行多次,从而有忧患!!!
- 如果硬要使用的话,前面加上
"UNSAFE_"
,即 UNSAFE_componentWillUpdate() 就不会出现 warning!!!
(2) render()
每次状态更新都会被调用执行!!!
so注意:
-
不要在 render() 中执行,setState() ,会造成死循环,因为状态更新,就会再次调用 render() ,同时就会再次执行setState()....
-
一般只做组件展示,只访问 state 和 props
(3) componentDidMount()
- 成功 render() 并渲染完成真实 DOM 之后触发
- 数据请求 ajax 、axios
- 订阅函数的调用
- setInterval()
- 可以在里面进行 DOM 节点的修改 ,BetterScroll(一个库,可以使 DOM 节点中的内容,更平缓的滚动!!)
<2> 运行中
(1) componentWillUpdate()
跟 componentWillMount()
一样已经不推荐使用了!!
(2) render()
不要在里面更新状态 setState()
(3) componentDidUpdate()
更新后执行,可以在里面获取 DOM 节点,并进行更新!!!
componentDidUpdate(preProps , preState)
- 该函数会收到两个参数,即更新前的属性和状态!!!
注意:
- 该生命周期函数跟 render() 一样会执行很多次,所以里面的操作也会执行很多次,考虑到性能问题,可以给部分操作加上判断条件,实现只在首次渲染执行一次的操作!!!
(4) shouldComponentUpdate() 性能优化函数
shouldComponentUpdate(nextProps , nextState)
该函数接收两个参数,想要更新的属性和状态!!
注意:
- 如果有多个状态,一个一个比太麻烦了,所以可以将整个状态对象转化为字符串进行对比。
JSON.stringify()
在子组件中用的多!!!
例如,我们要在父组件中遍历生成若干个我们自己写的 child 组件 ,如果我们不在子组件中做性能优化的话,那么每次父组件状态改变,导致子组件的重新 update 的话,有多少个子组件,就会 render() 多少次!!!!所以我们可以在子组件中使用 shouldComponentUpdate()
做性能优化,只有状态因为父组件的改变而跟着改变的子组件才用 render() !!!
注意:
前面提到的,不要直接 this.state.cnt = 1
修改状态的原因是,如果要用 shouldComponentUpdate(nextProps , nextState)
这个函数,那就要进行老状态与想要更新的状态的对比,如果直接修改的话,那么老状态就会被改变了,那么该函数就会变的毫无意义!!!
(5) componentWillReceiveProps(nextProps)
在子组件中使用!!!!
最先获得父组件传来的属性(nextProps),可以在该函数中对该传来的属性进行处理!!!AJAX or 逻辑处理(把属性转换为自己的状态...)!!!
<3> 销毁
(1) componentWillUnmount()
在组件被卸载之前进行一些清理操作,如清除计时器、关闭事件监听器!!!
二. 新生命周期
<1> getDerivedStateFromProps()
getDerivedStateFromProps(nextProps , nextState)
第一次的初始化组件 && 后续的更新过程中(包括自身状态更新以及父传子属性更新)都会执行该函数!!
返回一个 对象,作为新的 state ,会跟之前的 state 对象进行合并 ,即没有的添加,同名的进行更新!!
注意:
-
该函数为类上的静态方法,即使用要在前面加上
static
-
因为是类本身上的方法,所以无法在其内部使用
this
-
因为该函数返回新的 state 对象,所以在里面
发起请求,ajax、axios
是没有用的,因为该函数会直接执行返回的代码,即请求接收到的数据,是无法被即使作为新状态对象返回出去的!!!- 所以该函数可以配合 componentDidUpdate() 使用,即在该函数中把接收到的属性转化为自身的对象,然后在 componentDidUpdate() 进行使用!!
all in all:
- 该新的生命周期可以在初始化时代替
componentWillMount()
- 在父传子中可以代替
componentWillReceiveProps()
<2> getSnapshotBeforeUpdate()
触发时间为 update 发生的时候,执行时间为render()之后,DOM 发生更新之前 ,所以常常用来记录 DOM 更新之前的一些数据!!供更新后使用!!!
-
例如,用户在浏览邮箱页面,突然来了很多封新邮件,那么就需要对它们进行展示,而且是要展示在头部,所以如果不加处理用户正在看的地方就会被推到下面,为了更好的用户体验,我们希望,此时还保留在用户之前停留的页面!!!
- 就需要记录下之前的容器高度,然后在新的邮件进行展示后,将页面滚动到 `scrollTop = 此时容器高度 - 之前容器高度` !!
它可以很好地替代 componentWillUpdate()
,componentWillUpdate()
执行时间为 render() 之前,所以从记录之后到开始更新 DOM 之间间隔时间还挺长的,所以会导致记录的数据不准确!!!
- 该函数返回记录的数据,并且该返回的值会作为参数传入
componentDidUpdate()
,作为它的第三个参数,即componentDidUpdate(preProps , preState , value)
,方便在内部进行一些操作!!!