React基础与实践

96 阅读3分钟

1.关于React

React特点:声明式、组件化、跨平台

影响web性能的主要原因

等待资源加载时间和大部分情况下浏览器单线程执行是影响 web 性能的两大主要原因。

  • 对于一次请求太多资源?网络请求慢?使用React.Lazy&React.Suspense

  • 对于资源加载失败:使用ErrorBoundary

  • 对于JS 执行、浏览器计算样式布局、UI 绘制

    • 异步更新
    • 时间切片
    • React Fiber

react更新流程

  • Scheduler (调度器)

    • 维护时间切片 (类似requestldleCallback)
    • 与浏览器任务调度
    • 优先级调度
  • Reconciler (协调器)

    • 将JSX 转化为 Fiber
    • Fiber 树对比(双缓存)
    • 确定本次更新的 Fiber
  • Renderer (渲染器)

    • 渲染器用于管理一棵 React 树
    • 使其根据底层平台进行不同的调用。

298a16ab893a42bd8889f6f304d7ff27tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.webp

c0390709251b47858563d9b39b92a80atplv-k3u1fbpfcp-zoom-in-crop-mark1512000.webp

React优缺点

  • 优点

    • 快速响应: Fiber
    • 组件化:复用性强
    • 声明式编程
    • 跨平台: 只需修改渲染器【React-Native...】
  • 缺点?

    • 大型应用需要配套学习 状态管理、路由工具
    • 不适合小型应用,需要用 babel 处理

2.React基础

  • web应用&组件

35bed037415c4498a41cce15ecfa08edtplv-k3u1fbpfcp-zoom-in-crop-mark1512000.webp

组件

425ed004f7c54e38a00171f8ac59f5f2tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.webp

  • 类式组件

    • 继承+构造函数
    • this
    • 生命周期
    • render方法
  • 函数式组件

    • 没有生命周期,借助hook
    • return JSX

函数式组件相较于类式组件的优点:

  • 没有复杂的生命周期
  • 支持自定义 hook,逻辑复用方便

使用时:

  1. 将 UI 拆成多个独立单元,这些单元组合可以构成多种视图展示,这些独立单元就是组件。组件相当于原子。
  2. hook 贴近组件内部运行的各种概念逻辑,effect、state、context等。hooks 更贴切于电子。

问题:React怎么知道哪个state对应哪个 useState?

React 靠的是 Hook 调用的顺序,所以只能在最顶层使用 Hook。

错误写法

767bbaf706eb481688bc8842391e98datplv-k3u1fbpfcp-zoom-in-crop-mark1512000.webp

正确写法

ec867d6b9c874901bf0707a2913197abtplv-k3u1fbpfcp-zoom-in-crop-mark1512000.webp

Hook 规则 & 原理

  • 在 React函数组件中 或自定义 Hook 中调用
  • 自定义 Hook 必须以 use 开头
  • Hook 中的 state 是完全隔离的

React解决过期闭包问题

5bf6c84b5b964377b793f16f6e96e641tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.webp 在useEffect中设置依赖值,有变化就进行更新,解决过期闭包影响输出

3.场景案例

常见API及作用

649d1f528b7f4216b469de6e3a90cb56tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.webp

常见Hook及作用

a67da3a619fa4d27a5829e0d99076538tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.webp

组件划分:layout | page | component

组件间通信

父传子

  • 知道子组件的表现,直接通过 props 传递即可
  • 不知道具体子组件表现呢? 用props.children

d1b17802ffd049ce8a7d10f13e672e0ctplv-k3u1fbpfcp-zoom-in-crop-mark1512000.webp 写一个SizeWrapper组件,遍历子组件传递props,不用再分别在每一个子组件传递

子传父

子组件:将内容作为参数,放到父组件的回调函数中;在父组件:调用函数拿到结果值 2e8fc4a5c1564079bd0a3850d7e17628tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.webp 此处用了ref的转发:在子组件给ref添加方法和参数,通过forwardRef进行转发,父组件通过useRef取出,调用方法

组件间共享

  • reducer&context

a73bf7167ad8452a88f8a8ade0009abetplv-k3u1fbpfcp-zoom-in-crop-mark1512000.webp

  • react-redux

7a7bb313ada7401a87a6a89fae06cba9tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.webp

组件性能优化

三个组件:name counter calcvalue,只要有一个组件变化,整体全部重新渲染

67d044f4866f4466bf32880645fdc57dtplv-k3u1fbpfcp-zoom-in-crop-mark1512000.webp

优化1:用生命周期钩子比对

存在的问题:count可以直接比较,但是函数的比较一定是真,因为没有两个完全相等的函数,依旧会重新渲染

6cb6ddd45f5f4937b69dc345dd6fbd30tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.webp 优化1.1:使用useCallback便可以解决

723c0b61b94c4bbf991b4705f4c2507ftplv-k3u1fbpfcp-zoom-in-crop-mark1512000.webp

优化2:使用useMemo解决会重新计算函数值的情况

3436731dc2724672a0bb5995ff1f9950tplv-k3u1fbpfcp-zoom-in-crop-mark1512000.webp

组件挂载位置

实现:组件写在蓝色容器,实际挂载在黄色容器【相当于在一个组件内写了抽屉,另一个兄弟组件也能用】

3f8e1160e97441b7a98c075e948331eftplv-k3u1fbpfcp-zoom-in-crop-mark1512000.webp

使用reactPortal实现

64d51cd460b3433da3a937b63a14cacctplv-k3u1fbpfcp-zoom-in-crop-mark1512000.webp

冒泡问题:触发hide后会冒泡再自动触发show

f5e14b0ee37f4ed1bc75331fa783701etplv-k3u1fbpfcp-zoom-in-crop-mark1512000.webp 那么使用reactPortal后会冒泡至哪里?

79dbdb01f15543fa9183fdf3d13651ebtplv-k3u1fbpfcp-zoom-in-crop-mark1512000.webp

一个从 poral 内部触发的事件会一直冒泡至包含 React 树的祖先,即便这些元素并不是DOM树 中的祖先。所以会冒泡到蓝色盒子。

逻辑复用

实现基础请求、轮询请求、取消请求、更改轮询请求时间间隔

2c0d6dc0d98646809e2371b0b9a52ecbtplv-k3u1fbpfcp-zoom-in-crop-mark1512000.webp 步骤:

  • 设置hook的入参
  • 设置要用到的状态
  • 需调用的方法
  • 可变的时间、请求参数