React生命周期

453 阅读5分钟

1.引出生命周期

unmountComponentAtNode() 卸载组件

componentDidMount()组件挂载完毕

componentWillReceiveProps () 组件将要接受参数 (子组件将要接受新参数时触发的生命周期函数)

shouldComponentUpdate() 是否可以组件更新,必须有 Boolean 值得返回,如果为 true 则继续生命周期,如果为 false 则不执行任何后续操作,相当于更新操作的阀门

componentWillUpdate () 组件即将要更新

componentDidUpdate()组件更新完成

render()初始化渲染、状态更新之后执行人 render

componentWillUnmount()组件将要卸载

旧版本生命周期函数:

挂载时:(初始化操作时)

constructor => componentWillMount => render => componentDidMount => componentWillUnmount(卸载组件时触发更新)

更新时:(有三条路线)

  1. 正常更新操作时:setState 执行更新操作

    constructor => componentWillMount => render => componentDidMount => (setState 执行更新操作)=> shouldComponentUpdate => componentWillUpdate => render => componentDidUpdate => componentWillUnmount

  2. 强制更新操作:forceUpdate() 状态无更新,强制更新,不受 shouldComponentUpdate 阀门控制

    constructor => componentWillMount => render => componentDidMount => (forceUpdate 强制执行更新操作) => componentWillUpdate => render => componentDidUpdate => componentWillUnmount

  3. 父组件 render :当组件内部接收新参数时会触发 componentWillReceiveProps

    constructor => componentWillMount => render => componentDidMount => componentWillReceiveProps => shouldComponentUpdate => componentWillUpdate => render => componentDidUpdate => componentWillUnmount

2_react生命周期(旧).png 总结:react 的生命周期分三个阶段执行:

  1. 初始化阶段: 由ReactDOM.render()触发---初次渲染

1). constructor()

2). componentWillMount()

3). render()

4). componentDidMount() =====> 常用

=> 一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息

  1. 更新阶段: 由组件内部this.setSate()或父组件render触发

1). shouldComponentUpdate()

2). componentWillUpdate()

3). render() =====> 必须使用的一个

4). componentDidUpdate()

  1. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发

1). componentWillUnmount() =====> 常用

=> 一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息

新版本生命周期函数:

新版本生命周期更改了 componentWillReceiveProps ,componentWillMount,componentWillUpdate 的使用,使用时需增加前缀UNSAFE_标记生命周期方法“过时”。这些方法仍然有效,但不建议在新代码中使用它们。增加了 static getDerivedStateFromProps()静态方法,getSnapshotBeforeUpdate()

  • static getDerivedStateFromProps(props, state)getDerivedStateFromProps 会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容。此方法适用于罕见用例,即 state 的值在任何时候都取决于 props。但是派生状态会导致代码冗余,并使组件难以维护,不推荐使用
  • getSnapshotBeforeUpdate(prevProps, prevState)getSnapshotBeforeUpdate() 在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期方法的任何返回值将作为参数传递给 componentDidUpdate()。此用法并不常见,但它可能出现在 UI 处理中,如需要以特殊方式处理滚动位置的聊天线程等。该生命周期应返回 snapshot 的值(或 null)。

3_react生命周期(新).png

总结:

  1. 初始化阶段: 由ReactDOM.render()触发---初次渲染

1). constructor()

2). getDerivedStateFromProps ()

3). render()

4). componentDidMount() =====> 常用

一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息

  1. 更新阶段: 由组件内部this.setSate()或父组件重新render触发

1). getDerivedStateFromProps()

2). shouldComponentUpdate()

3). render()

4). getSnapshotBeforeUpdate()

5). componentDidUpdate()

  1. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发

1). componentWillUnmount() =====> 常用

一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息

常用生命周期函数:

常用生命周期函数.png

\1. render:初始化渲染或更新渲染调用

\2. componentDidMount:开启监听, 发送ajax请求

\3. componentWillUnmount:做一些收尾工作, 如: 清理定时器

即将废弃的生命周期函数:

\1. componentWillMount

\2. componentWillReceiveProps

\3. componentWillUpdate

现在使用会出现警告,下一个大版本需要加上UNSAFE_前缀才能使用,以后可能会被彻底废弃,不建议使用。

DOM 的 diffing 算法:

对比的最小粒度是标签,标签的内容会更新,但是标签内部的标签会作比较,未改变则不会更新,

key 的作用(内部原理):index 不建议使用,在某些条件下会有问题

经典面试题:

1). react/vue中的key有什么作用?(key的内部原理是什么?)

2). 为什么遍历列表时,key最好不要用index?

\1. 虚拟DOM中key的作用:

1). 简单的说: key是虚拟DOM对象的标识, 在更新显示时key起着极其重要的作用。

2). 详细的说: 当状态中的数据发生变化时,react会根据【新数据】生成【新的虚拟DOM】,

随后React进行【新虚拟DOM】与【旧虚拟DOM】的diff比较,比较规则如下:

a. 旧虚拟DOM中找到了与新虚拟DOM相同的key:

(1).若虚拟DOM中内容没变, 直接使用之前的真实DOM

(2).若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM

b. 旧虚拟DOM中未找到与新虚拟DOM相同的key

根据数据创建新的真实DOM,随后渲染到到页面

\2. 用index作为key可能会引发的问题:

\1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:

会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。

\2. 如果结构中还包含输入类的DOM:

会产生错误DOM更新 ==> 界面有问题。

\3. 注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,

仅用于渲染列表用于展示,使用index作为key是没有问题的。

\3. 开发中如何选择key?:

1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。

2.如果确定只是简单的展示数据,用index也是可以的。