React 核心总结

React 是什么?

用于构建界面的 javascript 库

特点:

  • 声明式
  • 组件式

优点:

  • 开发团队和社区非常强大
  • api 简洁

缺点:

  • 没有官方系统解决方案,选型成本高
  • 过于灵活,对代码设计要求高

jsx 是 React.createElement 的语法糖

React 的 class 组件和函数组件的区别

相同:都可以接收 props 并返回 react 对象

不同:

  • 编程思想和内存:类组件需要创建实例面向对象编程,它会保存实例,需要一定的内存开销,而函数组件面向函数式编程,可节约内存

  • 可测试性:函数式更利用编写单元测试

  • 捕获特性:函数组件具有值捕获特性(只能得到渲染前的值)

  • 状态:class 组件定义定义状态,函数式需要使用 useState

  • 生命周期:class 组件有完整的生命周期,而组件没有,可以用useEffect 实现类生命周期功能

  • 逻辑复用:类组件通过继承或者高阶组件实现逻辑复用,函数组件通过自定义组件实现复用

  • 跳过更新:类组件可以通过shouldComponents 和 PureComponents(浅比较,深比较可以用immer) 来跳过更新,函数组件react.memo 跳过更新

  • 发展前景:函数组件将成为主流,因为他更好屏蔽this问题,和复用逻辑,更好的适合时间分片和并发渲染

React 设计理念

  • 跨平台渲染=>虚拟dom
  • 快速响应=>异步可中断(fiber)+增量更新

fiber

fiber 是一个执行单元,每次执行完成一个执行单元,react 会检测当前帧还剩多少时间,如果没有时间就将控制器让出去

fiber 是一种数据结构

  • react 目前的做法使用链表,每个vdom结点内部表示为一个fider

  • 从顶点开始遍历

  • 如果有第一个儿子,则先遍历第一个儿子

  • 如果没有第一个儿子,则标志此结点遍历完成

  • 如果有弟弟则遍历弟弟

  • 如果没有弟弟,则返回父节点标志父节点遍历完成,如果有叔叔则遍历叔叔

  • 没有叔叔则遍历结束

(儿子=〉弟弟=〉叔叔)

fiber 出现背景

React15 架构不能支撑异步更新,当渲染出现大量的组件递归时间超过 16.7ms 就会出现卡帧

React16 架构可以分为三层:

  • Scheduler(调度器类似 requestIdleCallback 功能)— 调度任务的优先级,高优任务优先进入Reconciler

  • Reconciler(协调器)— 负责找出变化的组件

  • Renderer(渲染器)— 负责将变化的组件渲染到页面上

react 渲染过程分为三步骤

  • 调度

  • 调和

  • 提交(不可暂停)

fiber 实现关键原理

  • 基于requestIdleCallback,获取当前一帧还有剩余时间deedline,(将在浏览器的空闲时段内调用的函数排队)
  • 由于兼容性实际是用Messagechannel + requestAnimationFrame 模拟requestIdleCallback

effect 副作用,表示将要对一个dom 元素进行操作,副作用链就是子孙后代,作用倒挂fiber构建dom结点

fiber 的作用

  • 能够把可中断的任务切片处理。

  • 能够在父元素与子元素之间交错处理,以支持 React 中的布局。

  • 能够在render()中返回多个元素。

  • 更好地支持错误边界。

原理利用 requestIdleCallback 函数将在浏览器器的空闲时段内调用的函数排队。这使开发者能够在主事件循环上执⾏行行后台和低优先级⼯工作,⽽而不不会影响延迟关键事件,如动画和输⼊入响应。

fiber 递归流程

function performUnitOfWork(fiber) {
  // 执行beginWork

  if (fiber.child) {
    performUnitOfWork(fiber.child);
  }

  // 执行completeWork

  if (fiber.sibling) {
    performUnitOfWork(fiber.sibling);
  }
}
复制代码

React 与 Vue 的区别

相同:

  • 都是前端界面实现 javascript 库

  • 都可以实现数据驱动模版更新,而不需直接操作dom,核心都是 vdom

不同:

  • Vue通过数据劫持,当数据改动时,界面就会自动更新,而React里面需要调用方法setState。

  • Vue 的更新的颗粒度是当前组件,而React除了当前组件还包括子组件(会有性能瓶颈)

  • 在设计上,Vue 数据和模版和方法是分开的,而 React 不分开,Vue 会有很多的指令,React 只有 js

  • 从 diff 上,当 Vue 的className不一致是认为不同的结点,而 React 认为是同一个结点,Vue 有头头,尾尾,交叉对比,而 React 没有。

  • React16 之后版本有 fider 之后可以实现异步切片更新

  • React 难得是它没有类似vue现成的全家桶技术栈,需要自己去选择和衡量,这就需要时间去踩坑,而且 React 周边使用起来并不太简洁明朗,需要了解所选周边的编写方式和最佳实践,这就耗费时间和增加入门门槛了

  • React 的生态比 Vue 完善

hook

Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数,可以使你在函数组件使用状态。

setState 是异步还是同步

React的setState本身并不是异步的,是因为其批处理机制给人一种异步的假象。

【React的更新机制】

生命周期函数和合成事件中:

  1. 无论调用多少次setState,都不会立即执行更新。而是将要更新的state存入'_pendingStateQuene',将要更新的组件存入'dirtyComponent';
  2. 当根组件didMount后,批处理机制更新为false。此时再取出'_pendingStateQuene'和'dirtyComponent'中的state和组件进行合并更新;

原生事件和异步代码中:

  1. 原生事件(原生js绑定的事件)不会触发react的批处理机制,因而调用setState会直接更新;
  2. 异步代码中调用setState,由于js的异步处理机制,异步代码会暂存,等待同步代码执行完毕再执行,此时react的批处理机制已经结束,因而直接更新。

总结:
react会表现出同步和异步(setTimeout/setInterval)的现象,但本质上是同步的,是其批处理机制造成了一种异步的假象。(其实完全可以在开发过程中,在合成事件和生命周期函数里,完全可以将其视为异步)

React 合成事件

16 事件流(没有分别注册捕获和冒泡事件 bug )

bug :点击弹窗没反应

原因:点击事件直接冒泡到 document 原生事件了,state 变成了 false

解决:

原理:

17 事件流

事件委托不再是 document 而是 挂载点容器,可以让一个页面可以使用多个 React 版本

不挂载到 document ,结点变成父子关系所以,stopPropagation(阻止冒泡) 生效

redux

什么时候使用redux:

  • 某个组件的状态,需要共享
  • 某个状态需要在任何地方都可以拿到
  • 一个组件需要改变全局状态
  • 一个组件需要改变另一个组件的状态

猜你喜欢

转载自juejin.im/post/7035069669476139044