likes
comments
collection
share

React之Fiber及setState简述

作者站长头像
站长
· 阅读数 16

Fiber

React16 之前的版本,更新过程是同步的,可能导致性能问题,例如更新一个组件需要 1ms,有 200 个组件需要更新那就需要 200ms,而这 200ms 期间是做不了其他事情的。

例如这 200ms 内往 input 框中输入内容你会发现没有反应,200ms 之后啪的一下全出来了,这就是页面卡顿!

什么是 Fiber

React Fiber 是对 React16 对 React 核心算法的一次重新实现!Fiber 会使原本同步的渲染过程变成异步的。

Fiber 会将一个大的更新任务拆解为许多个小任务,每当处理完一个小任务,渲染线程都会把主线程交出去,看看有没有优先级更高的工作要处理,确保不会出现其他任务被饿死的情况,进而避免同步渲染带来的卡顿!这个过程中渲染线程是可以被打断的,这就是所谓的异步渲染!

维护每一个分片的数据结构,就是 Fiber。

生命周期

projects.wojtekmaj.pl/react-lifec…

  1. Fiber 架构的重要特征就是渲染线程可以被打断的异步渲染模式,根据“能否被打断”这一标准,React16 的生命周期被划分为了 render 和 commit 两个阶段。

  2. render 阶段在执行过程中允许被打断,而 commit 阶段则总是同步执行的。render 阶段的操作对用户来说其实是不可见的,所以就算打断再重启对用户来说也是零感知,而 commit 阶段的操作则涉及真实 dom 的渲染,再狂的框架也不敢在用户眼皮子底下胡乱修改视图,所以这个阶段必须是同步的,来求稳。

  3. render 阶段是允许暂停、终止和重启!这就导致 render 阶段的生命周期都是有可能被重复执行的。而 React16 废弃的 componentWillMount、componentWillUpdate、componentWillReceiveProps 都是处于 render 阶段,都可能重复执行。这些 api 经常被滥用,他们在重复执行的过程当中可能会存在风险!

骚操作例如 setState、fetch 发起异步请求、操作真实 DOM...,完全可以转移到其他声明周期(尤其是 componentDid...)里去做。

  1. 比如在 componentWillMount 里发起异步请求,很多同学由于太年轻,以为这样做就可以让异步请求回来的早一点,从而避免白屏,可是异步请求再怎么快,也快不过同步的生命周期,componentWillMount 结束后,render 会迅速的被触发,所以说首次渲染依然会在数据返回之前执行,这样做不但没有达到目的,还会导致服务端渲染场景下的冗余请求等额外问题。

  2. 在 Fiber 带来的异步渲染机制下,旧的生命周期可能还会导致严重的 Bug,由于 render 阶段里的生命周期都可以重复执行,在 componentWillxxx 被打断 + 重启多次后,就会发出多个付款请求。又或者你习惯在 componentWillReceiveProps 里操作 dom,那么此钩子若是执行了 2 次,你可能会一口气删除掉 2 个 dom 元素。

  3. getDerivedStateFromProps 作为静态方法存在,里面触碰不到 this,就是为了避免各种危险的骚操作。

  4. 即使你没有开启异步,React15 下也有不少人能把自己玩死,比如在 componentWillUpdate 里滥用 setState 导致重复渲染死循环,懂得都懂。

  5. 总之,React16 改造生命周期的主要动机是为了配合 Fiber 架构带来的异步渲染机制,针对生命周期中长期被滥用的部分推行了具有强制性的最佳实战!Fiber 机制下确保了数据和视图的安全性,同时也确保了生命周期方法的行为更加纯粹、可控、可预测!

现有的生命周期,虽然已经对方法的最佳实战做了强约束,但是仍然无法覆盖所有的“误操作”

zh-hans.reactjs.org/blog/2018/0…

初始化:constructorgetDerivedStateFromPropsrendercomponentDidMount

更新:getDerivedStateFromPropsshouldComponentUpdaterendergetSnapshotBeforeUpdatecomponentDidUpdate

销毁:componentWillUnmount

Hooks

  1. Hooks 一类特殊的函数,目的之一是:为你的函数式组件注入特殊的功能和状态!第二是为了更好的代码复用!

  2. React Hooks 背后涉及对类组件和函数组件两种组件形式的思考和侧重。

  3. 类组件与函数组件不同

类组件需要继承 class,函数组件不需要;

类组件可以访问生命周期方法,函数组件不能;

类组件可以获取到实例化后的 this,并基于这个 this 做各种各样的事情,而函数组件不能;

类组件中可以定义并维护 state(状态),而函数组件不可以;

  1. 类组件,是面向对象编程思想的一种表征

封装:将一类属性和方法,“聚拢”到一个 Class 里去

继承:新的 Class 可以通过继承旧的 Class 实现对某一类属性和方法的复用

  1. 但 “多” 就是 “好” 吗

函数式组件:轻量、灵活、易于组织和维护

函数组件会捕获 render 内部的状态,这是两类组件最大的不同!函数组件真正的把数据和渲染绑定到了一起。

函数组件更加契合 React 框架的设计理念,UI = f(data),React 组件本身的定位就是函数,一个吃进数据,吐出 UI 的函数。

  1. React Hooks 的出现是为了强化函数式组件的能力,那么为什么需要函数式组件呢?

告别难以理解的 class,例如 this 和 生命周期

解决业务逻辑难以拆分的问题

使状态和逻辑复用变得简单可行

函数组件从设计思想上来看,更加契合 React 的理念

setState

  • 异步更新,同步执行!
  • setState 在合成事件和钩子函数中是“异步”的,在原生事件和 setTimeout 中是同步的。
  • setState 的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中不能直接拿到更新后的值,形成了所谓的“异步”,当然也可以通过 setState 的第二个参数 callback 的回调中拿到更新后的结果。
  • setState 的批量更新优化也是建立在“异步”(合成事件、钩子函数)之上的,在原生事件和 setTimeout 中不会批量更新,在“异步”中如果对同一个值进行多次 setState, setState 的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同时 setState 多个不同的值,在更新时会对其进行合并批量更新。
转载自:https://juejin.cn/post/7159225656675401764
评论
请登录