React简述 | 青训营笔记

89 阅读4分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 6 天

React入门

历史与应用

React应用:

  • 前端网页
  • 移动端 React Native
  • Electron
  • React Three Fiber

发展历史:

React前身是FaxJS, React 的特性也是在不断加强FaxJS的特性

FaxJS特性:

  • 支持客户端与服务端渲染
  • 响应式
  • 高性能
  • 结构化

React设计思路

原生JS的痛点

  • 状态更新, UI 需要自己手动调用DOM API 进行更改

  • 代码层面无封装、隔离, 代码层面无组件化概念

  • UI 之间的数据依赖关系需要手动维护, 不能一个改变另外的可以跟着一块变, 依赖链路过长会遇到回调地狱

响应式与转换式

转换式系统

例子: 编译器

给定输入求解出输出

响应式系统

例子: UI 界面

监听事件, 消息驱动, 事件响应

graph LR
id1[事件发生] --> id2["执行回调 (响应事件)"] --> id3["状态变更 (可能是回调函数导致)"]

前端 UI:

graph LR
id1[事件发生] --> id2["执行回调 (响应事件)"] --> id3["状态变更 (可能是回调函数导致)"] --> id4[UI更新]

期望

  • 状态更新, UI 也更新

  • 代码可以语义化组件, 可复用, 可封装

  • 状态之间的依赖关系不需要手动维护, 声明即可

    例如: A=B+C, 若BC中任意一个变动, A就会自动赋值为B+C, 不需要手动计算

组件化准则

  1. 组件是组件的组合或者是原子组件

  2. 组件内有自己的状态, 外部不可见

  3. 父组件可以将状态传入到组件内部 (父组件应能控制子组件) (接口化)

组件化的设计

  1. 组件声明了状态与 UI 的映射 (输入几个状态返回一个 UI)
  2. 组件有 Props 和 State 两种状态
  3. 组件可以是其他组件拼装而成

省流: 组件内有自己的私有状态 (State) 并且能够接受外部的参数 (Props) 来提高复用性, 最后根据现有的 State 与 Props 返回一个 UI

React 生命周期

图片.png

React Hooks 写法

Effect --- 副作用 useEffect()

组件内单纯执行类似于const a = b + c这种不会影响组件外部的语句 会给组件外部造成影响的 发起网络请求 (与外部系统交互) 操作sessionStorage或者localStorage等 纯函数, 1+2=3这种, 跟组件外无交互的

副作用函数:

()=>{
  document.title = 'Title';
}

react 里如果需要使用副作用执行的, 需要使用useEffect(effectFunc)函数

import React, { useState, useEffect } from 'react';
function Example() {
  const [count, setCount] = useState(0);
  
  // 在这段代码里, useEffect() 会在组件 Mount 时执行
  // 对应上面生命周期的 Mounting - componentDidMount
  // 也就是说只会执行一次
  useEffect(()=>{
    document.title = `你点击了 ${count} 次`;
  });
  
  return (
    <div>
      <p>你点击了 {count} 次!</p>
      <button onClick={ ()=>setCount(count + 1) } >
        点我
      </button>
    </div>
  );
}

react 在组件 mount 时与依赖项被 set 时会执行 useEffect(func, depend) 的函数

Hooks

可以挂载到 react 组件生命周期上执行的函数 例如 useEffect, useState这种都是hooks

使用法则

不要再循环, 条件, 嵌套函数内使用 hooks

指令式&声明式&响应式

  • 指令式 一步步告诉如何操作
  • 声明式 发出指令自动干活
  • 响应式 是声明式编程的类别, 不仅可以自动干活, 还可以根据状态自动去触发

React的实现

JSX不符合JS标准

将 JSX 转译为 JS

返回的JSX发生改变时如何更新DOM

使用虚拟DOM, 虚拟DOM是一种用于和真实DOM同步, 但是在JS内存中维护的一个对象, 具有和DOM类似的树状结构, 并和DOM建立一一对应的关系

可以告诉React UI的状态, 就能确保DOM匹配该状态, 从而从手动DOM, 事件处理中解放出来

更新DOM流程

图片.png

diff

算法太差, 大部分略........

Heuristic O(n) Algorithm

两棵树从根开始递归比对, 三条规则:

  • 不同类型的元素: 替换
  • 同类型的DOM元素: 更新
  • 同类型的组件元素: 递归

React状态管理

核心思想

图片.png

将状态抽到 UI 外部进行统一管理

个人理解 Vue 的 VuexPinia也一样的思想

缺点: 增强了组件与store的耦合

状态管理库推荐 (ps: 用哪个都可以, 除非特别大)

  • Redux (讲师: 设计有些问题, 新的比它好?) 使用时可以去看看对应版本的评价
  • xstate (基于状态机思想)
  • mobx
  • recoil

状态机思想

graph LR
id1[当前状态] --> id2[收到外部事件] --> id3[状态迁移或转换]

应用场景

整个App所拥有的放到Store里, 单独组件拥有的不放

Modern.js/Reduck

Modern.js 基于 React 的全栈开发框架, Reduck 是其内部的状态管理库

运用方式

省流, 和Pinia差不多, 参考代码如下:

// 定义 Model
import { model } from '@modern-js/runtime/model';

const countModel = model('count').define({
  state: {
    x: 0,
    y: 0,
    sum: 0,
  },
  actions: {
    incrementX(state) {
      state.x += 1;
    },
    incrementY(state) {
      state.y += 1;
    },
  },
});

export default countModel;


// 使用 Model
import { useModel } from '@modern-js/runtime/model';

// [ <state>, <actions> ]
const [{x, y}, {incrementX, incrementY}] = useModel(countModel);

// 获取 state
console.log(x);
console.log(y);

// 调用 actions
incrementX()
incrementY()

应用级框架推荐

  1. Next.js
  2. Modern.js
  3. Blitz 无API思想的全栈开发框架, 开发过程无需写API与CURD逻辑, 适合前后端紧密结合的小团队项目