react的生命周期,以及有哪些改变,为什么去掉了旧的生命周期?

一、react生命周期函数的变化

新的生命周期增加了static getDerivedStateFromProps()以及getSnapshotBeforeUpdate(),废弃了原有的componentWillMount()componentWillUpdate()以及componentWillReceiveProps()

分别如以下图

原生命周期:

在这里插入图片描述

新生命周期(图引用自React v16.3之后的组件生命周期函数):

在这里插入图片描述

二、为什么数据获取要在componentDidMount中进行?

首先,分析一下两者请求数据的区别:

componentWillMount获取数据:

  1. 执行willMount函数,等待数据返回
  2. 执行render函数
  3. 执行didMount函数
  4. 数据返回, 执行render

didMount获取数据:

  1. 执行willMount函数
  2. 执行render函数
  3. 执行didMount函数, 等待数据返回
  4. 数据返回, 执行render

很明显,在willMount中获取数据,可以节省时间(render函数和didMount函数的执行时间),但是为什么我们还要在didMount中获取数据

  1. 如果使用服务端渲染的话,willMount会在服务端和客户端各自执行一次,这会导致请求两次(接受不了~),而didMount只会在客户端进行
  2. 在Fiber之后, 由于任务可中断,willMount可能会被执行多次(fiber算法是异步渲染,异步的渲染,很可能因为高优先级任务的出现而打断现有任务导致componentWillMount就可能执行多次)
  3. willMount会被废弃,目前被标记为不安全
  4. 节省的时间非常少,跟其他的延迟情况相比,这个优化可以使用九牛一毛的形容(为了这么一点时间而一直不跟进技术的发展,得不偿失),并且render函数是肯定比异步数据到达先执行,白屏时间并不能减少

关于第一点,如果你想在服务端渲染时先完成数据的展示再一次性给用户,官方的推荐做法是用constructor代替willMount

为什么要改变生命周期

从上面的生命周期的图中可以看出,被废弃的三个函数都是在render之前,因为fiber的出现,很可能因为高优先级任务的出现而打断现有任务导致它们会被执行多次

另外的一个原因则是,React想约束使用者,好的框架能够让人不得已写出容易维护和扩展的代码,这一点又是从何谈起,我们可以从新增加以及即将废弃的生命周期分析入手

componentWillMount()

首先这个函数的功能完全可以使用componentDidMount和constructor来代替,异步获取的数据的情况上面已经说明了,而如果抛去异步获取数据,其余的即是初始化而已,这些功能都可以在constructor中执行,除此之外,如果我们在willMount中订阅事件,但在服务端这并不会执行willUnMount事件,也就是说服务端会导致内存泄漏

所以componentWillMount完全可以不使用,但使用者有时候难免因为各种各样的情况(如作者犯浑)在componentWillMount中做一些操作,那么React为了约束开发者,干脆就抛掉了这个API

componentWillReceiveProps()

在老版本的 React 中,如果组件自身的某个 state 跟其 props 密切相关的话,一直都没有一种很优雅的处理方式去更新 state,而是需要在 componentWillReceiveProps 中判断前后两个 props 是否相同,如果不同再将新的 props 更新到相应的 state 上去。这样做一来会破坏 state 数据的单一数据源,导致组件状态变得不可预测,另一方面也会增加组件的重绘次数。类似的业务需求也有很多,如一个可以横向滑动的列表,当前高亮的 Tab 显然隶属于列表自身的状态,但很多情况下,业务需求会要求从外部跳转至列表时,根据传入的某个值,直接定位到某个 Tab。

为了解决这些问题,React引入了第一个新的生命周期

static getDerivedStateFromProps(nextProps, prevState) .//返回一个对象 和调用setState一样

可以先看一下两者在使用上的区别:

原有的代码

componentWillReceiveProps(nextProps){
 if(nextProps.tab!=this.props.tab){
  this.setState({
    tab:nextProps.tab
  });
  this.tabChange();
 }
}

新的代码

static getDerivedStateFromPorps (nextProps,prevState){
 //2
 if(nextProps.tab!=prevState.tab){
   return {
    tab:nextProps.tab
   };
 }
 return null;
}

componentDidUpdate(prevProps,prevState){
  this.tabChange();
}

这样看似乎没有什么改变,特别是当我们把this,tabChange也放在didUpdate中执行时(正确做法),完全没有不同,但这也是我们一开始想说的,React通过API来约束开发者写出更好的代码,而新的使用方法有以下的优点

  1. getDSFP是静态方法,在这里不能使用this,也就是一个纯函数,开发者不能写出副作用的代码
  2. 开发者只能通过prevState而不是prevProps来做对比,保证了state和props之间的简单关系以及不需要处理第一次渲染时prevProps为空的情况
  3. 基于第一点,将状态变化(setState)和昂贵操作(tabChange)区分开,更加便于 render 和 commit 阶段操作或者说优化。

componentWillUpdate()

与 componentWillReceiveProps 类似,许多开发者也会在 componentWillUpdate 中根据 props 的变化去触发一些回调。但不论是 componentWillReceiveProps 还是 componentWillUpdate,都有可能在一次更新中被调用多次,也就是说写在这里的回调函数也有可能会被调用多次,这显然是不可取的。与 componentDidMount 类似,componentDidUpdate 也不存在这样的问题,一次更新中 componentDidUpdate 只会被调用一次,所以将原先写在 componentWillUpdate 中的回调迁移至 componentDidUpdate 就可以解决这个问题。

另外一种情况则是我们需要获取DOM元素状态,但是由于在fiber中,render可打断,可能在willMount中获取到的元素状态很可能与实际需要的不同,这个通常可以使用第二个新增的生命函数的解决

getSnapshotBeforeUpdate(prevProps, prevState) // 返回的值作为componentDidUpdate的第三个参数

与willMount不同的是, getSnapshotBeforeUpdate会在最终确定的render执行之前执行,也就是能保证其获取到的元素状态与didUpdate中获取到的元素状态相同,这里官方提供了一段参考代码:

在这里插入图片描述

总结:

随着React Fiber的落地,许多功能都将开始改变,但本质上是换汤不换药,很多时候都是React为了开发者写出更好的代码而做的改变,当然这也是React的厉害之处,通过框架来约束开发者!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
React 组件的生命周期方法包括以下几个阶段: 1. Mounting(挂载阶段): - constructor:组件被创建时调用,用于初始化状态和绑定事件处理函数。 - static getDerivedStateFromProps:在组件实例化和接收新的 props 时被调用,用于更新状态。 - render:根据组件的状态和属性返回 JSX 元素。 - componentDidMount:组件被挂载到 DOM 后调用,可以进行异步操作和与外部库集成。 2. Updating(更新阶段): - static getDerivedStateFromProps:在接收新的 props 或者 state 发生变化时被调用,用于更新状态。 - shouldComponentUpdate:在重新渲染前被调用,用于控制是否需要重新渲染,默认返回 true。 - render:根据组件的状态和属性返回 JSX 元素。 - getSnapshotBeforeUpdate:在 render 方法执行之后、更新 DOM 之前调用,用于获取更新前的 DOM 信息。 - componentDidUpdate:组件更新后被调用,可以进行 DOM 操作和与外部库集成。 3. Unmounting(卸载阶段): - componentWillUnmount:组件从 DOM 中移除之前调用,用于清理定时器、取消订阅等操作。 4. Error Handling(错误处理阶段): - static getDerivedStateFromError:当子组件抛出错误时被调用,返回一个新的状态值。 - componentDidCatch:当子组件抛出错误时被调用,用于记录错误信息或发送错误报告。 需要注意的是,React 16.3 之前的版本还包括一些已被废弃的生命周期方法,如 componentWillMount、componentWillReceiveProps 等。在最新版本的 React 中,推荐使用新的生命周期方法替代这些废弃的方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宫商羽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值