一、什么是react?什么是react生命周期?

什么是react?

react介绍

我们先来看看 react官网 怎么介绍react:

  • 声明式:React 使创建交互式 UI 变得轻而易举。为你应用的每一个状态设计简洁的视图,当数据变动时 React 能高效更新并渲染合适的组件。以声明式编写 UI,可以让你的代码更加可靠,且方便调试。
  • 组件化:构建管理自身状态的封装组件,然后对其组合以构成复杂的 UI。由于组件逻辑使用 JavaScript 编写而非模板,因此你可以轻松地在应用中传递数据,并保持状态与 DOM 分离。
  • 一次学习,跨平台编写:无论你现在使用什么技术栈,在无需重写现有代码的前提下,通过引入 React 来开发新功能。React 还可以使用 Node 进行服务器渲染,或使用 React Native 开发原生移动应用。

我们在来看看目前react的热度:

The State of JS 近期(报告数据截止2022年底)对近 40,000 名 Web 开发人员的调查结果再次显示了,React 仍然是使用最广泛的前端框架,使用率为 81.8%,领先于 Angular(48.8%) 和 Vue(46.2)。(ps:在这个调查中:在回答有关 JavaScript 编程风格问题的人中,TypeScript 的使用率高达 98.9%);

ps:当然了这些数据是国外调查的,和国内的使用具体情况多多少少会有点偏差,但是总体上 react 依旧是主流;

The State of JS 2022: Front-end Frameworks

个人对react的理解

说白了react就是我们可以在一个jsx文件里面,既写js又写dom(虚拟),把其结合起来形成一个组件,以一个个组件的形式形去开发,形成我们项目;而且react通过对dom模拟使用了虚拟dom,最大限度的减少与dom的交互;

虚拟dom是什么?

虚拟DOM本质上是一个js对象,通过对象来表示真实的DOM结构

要想了解虚拟dom存在的意义,就要先知道浏览器dom渲染过程:构建dom树,构建cssom树,把dom树和cssom树结合起来构建render树,然后布局,最后合成图层显示在屏幕上;

如果每次都时刻去进行dom操作,例如突然来一个遍历10w次dom操作,对性能方面真的很浪费,但是有了虚拟dom就不一样了,我们可以先在虚拟dom对象上先进行操作(diff算法)(因为是虚拟的,不会每次变更就触发重新渲染),等在这个虚拟dom上完成操作在挂载到真实的dom上(创建一个新节点、删除原先节点、将新节点挂载上去),再去更新,性能不比渲染10w次dom香,另外由于虚拟dom保存的是js对象,天然的具有跨平台的能力,而不仅仅局限于浏览器;

jsx是什么?

jsx是js的语法扩展,它充分具备JavaScript的能力,是js的扩展版(js能做的,jsx也能做,js不能做的,jsx也能做),运用于react架构中

当然你在浏览器、node等上是无法直接编译运行jsx文件的,需要借助babel去将jsx转译成js去运行,不然你以为在jsx上面写一些dom能直接用呀,jsx结合上react具体编译如下:

  • jsx会被编译成React.createElement(),React.createElement()返回的是一个ReactElement 对象实例,这个对象实例本质上是一个以JavaScript形式存在的对dom描述的,就是虚拟dom;
  • ReactDOM.render()将虚拟dom渲染处理真实dom

jsx可以提高我们代码的可阅读性,提高我们的开发效率,不用使用React.createElement()去开发

jsx都知道是啥了,学过ts的应该知道tsx是啥吧,不展开啦!

react的生命周期

何为生命周期呢?

万事万物都有创建到销毁的过程,这一个过程就叫做生命周期,react 也有自己的生命周期,要想在react开发过程中对性能有高要求,那就必须对 react 的生命周期足够的了解,你必须了解 react 是如何从挂载渲染最后再到卸载的;

认识react的生命周期

ps:我们下面讲的主要是react中类的生命周期,函数式组件是没有生命周期函数的(当然在后面章节介绍函数式组件中我会谈谈如何通过hooks来模拟生命周期)

生命周期的三个阶段

  • 挂载(Mounting):这是一个组件被初始化创建到最后插入到dom中的过程;
  • 渲染/更新(Updating):这是一个组件中state或props发生变更后到重新提交到dom中的过程;
  • 卸载(Unmounting):这是将组件从dom中移除的过程

1、挂载--Mounting(开始环节)

这是react组件的生命周期中的第一个环节,这个环节相关周期函数如下

constructor 

constructor()这个环节我们的组件进行中了初始化的工作,例如对组件的 state 进行初始化,这个方法只会执行一次,在这个生命周期函数中,我们可以直接对this.state进行赋值(其他生命周期函数中如果想要修改state的话要使用this.setState

我们一般使用这个生命周期做什么?

  • super(props)操作;
  • 定义this.state

注意:

  • 在这个生命周期中我们接受propscontext,我们想要在当前组件下使用的话就需要在super传人参数,不然再该组件中无法正常去使用props
  • 同时我们要避免将props的值赋给state,毫无必要你完全可以直接使用this.props,你把props赋给state然后使用的是state,那当props发生变更时,state并不会影响受到影响的,别瞎折腾!!!
constructor(props) {
 super(props);
 this.state = {
   color: props.color  // 别瞎折腾,这是错误的🙅
 };
}

componentWillMount (16.9后弃用)

在组件挂载至 DOM 之前调用,并且只会调用一次。它在render方法之前调用,因此在componentWillMount中调用this.setState不会触发额外的渲染;

我们一般会在这个生命周期做什么?

在 componentWillMount 中引入订阅内容吧,哎呀很少人用,不推荐用

注意:

细心的同学看上面的生命周期图会发现没有componentWillMount这个钩子,在react 16.9版本之后就被弃用了,虽然你还可以用,但是控制台会有警告

为啥弃用componentWillMount

因为新的异步架构会导致它被多次调用,所以网络请求以及事件绑定应该放到 componentDidMount 中,React想约束使用者,让大家写出容易维护和扩展的代码的代码吧(个人理解,欢迎讨论)

当然弃用的还包括我们后面说的componentWillUpdatecomponentWillReceiveProps 道理一样他们有可能会多次调用

那有什么可以替代上面说的三个生命周期函数吗?

有,react16.3 中推出了 getDerivedStateFromProps

render(必要)

render() 方法是类组件中唯一必须实现的方法,它的返回值将作为页面渲染的视图。render 函数应该为纯函数,也就是对于相同的 state 和 props,它总是返回相同的渲染结果。
render 函数被调用时,会返回以下四种类型之一:

  • 通过jsx创建的react元素(主要是这种)
  • 数组或者fragments:使得render可以返回多个元素
  • Portals:可以渲染子节点到不同的dom树上
  • 字符串或数值类型:他们在dom中会被渲染为文本节点
  • 布尔类型或者null:什么都不渲染

componentDidMount(常用)

在完成render()后接下来就是compomentDidMount(),他在组件被插到dom树上后(发生在浏览器更新视图之前)立即调用,该方法也只会执行一次;

我们一般会在这个生命周期做什么?

这个生命周期函数使用频率就高了,一般我们会在上面做ajax请求,然后通过请求返回的数据去更新state使组件重新渲染,或者在这个阶段做一些订阅例如监听事件

注意:

  • compomentDidMount()中使用this.setState()会触发额外的渲染再一次调用render函数,但是浏览器中的视图更新只会执行一次;
  • 我们在compomentDidMount()中做订阅,一定要记得在conponentWillUnmount()中取消订阅啊!!!

2、更新 -- Updating(运行中的环节)

这是react组件的生命周期中的运行中的环节,只要组件不卸载,这个环节就会一直在,这个环节相关周期函数如下:

ps:在这个阶段的生命周期勾子函数使用setState一点要非常非常慎重,最好不用吧,就算要用也要加上判断逻辑,不然就陷入死循环了,那不就gg了!!!

componentWillReceiveProps(旧生命周期 - 16.9后弃用)

当已经挂载的组件中的props发生变更就会触发,在这个函数中你可以比较新旧两个props的区别,进而去修改state,但这破坏了props数据的单一数据源。

我们一般在这个生命周期做什么?

这个函数中你可以比较新旧两个props的区别,进而去修改state,但这破坏了props数据的单一数据源,前面我们也说了不建议使用!

注意:

  • this.setState 并不会触发这个生命周期被调用;
  • 在首次渲染组件时(Mounting阶段),不会调用这个组件;
  • 如果父组件渲染导致组件重新渲染,及时该组件的props没有变化,该生命周期也会被调用;

反正我们一般不用它

shouldComponentUpdate

render前调用,当props或state发生变化之前(即将变更但还没有变的时候)就会触发该组件的调用,默认返回的是 true,当你改为返回 false 时,那么不会更新组件,也就是不会执行后面的render,它接受nextPropsnextState两个参数,我们可以将 this.props(旧) 和 nextProps(新) 进行比较;

我们一般在这生命周期做什么?

生命周期方法通常用来做性能优化,我们可以在这个生命周期进行函数,例如可以将this.propsnextProps比较,以及将this.statenextState比较,并返回 false,让组件跳过更新;

注意:

  • 当你返回false时,它只会阻止当前组件的更新,但是不会阻止子组件因为state的改变而导致的更新
  • 我们上面说shouldComponentUpdate可以先对比值有没有变更在判断要不要更新,这个工作我们其实可以不用自己去写,也可以继承pureComponent来性能优化,pureComponent会帮你比较props或state有没有变更,有变更在调用shouldComponentUpdate
  • 如果你的state或props经常时会变的那就别瞎优化了,别继承pureComponent,你以为对是值否发生变化不需要时间呀;
shouldComponentUpdate(nextProps, nextState) {
  if (nextState.name !== this.state.name) {
    return true
  }
  return false
}

componentWillUpdate(旧生命周期 - 16.9后弃用)

当props或state发生变化后(已发送state或props变更),此时就会调用这个生命周期函数;

我们一般在这个生命周期做什么?

哎呀,感觉没什么用

我们可以用componentDidUpdategetSnapshotBeforeUpdate代替这个生命周期。如果你在此方法中读取 DOM 信息(例如,为了保存渲染前的dom宽度),则可以将此逻辑移至getSnapshotBeforeUpdate()中。

getSnapshotBeforeUpdate(新生命周期 - 16.3后引入)

getSnapshotBeforeupdate在最后一次渲染(提交到dom节点)之前调用,替换componetnWillUpdate;

此生命周期函数在最近一次渲染提交至 dom 树之前执行,此时 dom 树还未改变,我们可以在这里获取 dom 改变前的信息,例如:更新前 dom 的滚动位置。
它接收两个参数,分别是:prevPropsprevState,上一个状态的 props 和上一个状态的 state。它的返回值将会传递给 componentDidUpdate 生命周期钩子的第三个参数。

我们一般在这个生命周期做什么呢?

需要获取更新前 DOM 的信息时。例如:需要以特殊方式处理滚动位置的聊天线程等。

注意:

如果return false的话,则componentDidUpdate不会被回调

componentDidUpdate(常用)

componentDidUpdate在重新渲染完成后调用;

它接收两个参数,分别是:prevPropsprevStatesnapshot,上一个状态的 props 、上一个状态的 state、getSnapshotBeforeupdate给他return的参数(默认undefined)

3、卸载 -- Unmounting(卸载中的环节)

当组件从 dom 中移除时开启这个环节

componenWillUnmount(常用)

componentWillUnmount在组件卸载和销毁之前调用

我们一般在这个生命周期做什么呢?

我们想要在这一步去做一些清楚的动作,例如清除定时器、延时器、监听事件、网络请求、音/视频播放销毁、取消相关订阅;

注意:

这是一个必须的,减少bug发生的好编程习惯,一定要有,不要以为组件销毁了就拍拍屁股走人!!!

4、新的生命周期补充

getDerivedStateFromProps(新生命周期 - 16.3后补充,不建议用)

虽然不建议用当时还是讲下:

getDerivedStateFromProps是一个静态方法,接收 nextProps 和 prevState 两个参数。它会在调用 render 方法之前被调用,不管是在初始挂载时还是在后续组件更新时都会被调用。

static getDerivedStateFromProps(nextProps, prevState) {
    const {name} = nextProps;
    // 当传入的name发生变化的时候,更新state
    if (name !== prevState.name) {
        return {
            name,
        };
    }
    // 否则,对于state不进行任何操作
    return null;
}

参考文档

react 官方文档

The State of JS 2022: Front-end Frameworks

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值