响应式系统与React|青训营笔记

99 阅读3分钟

这是我参与「第四届青训营 」笔记创作活动的的第14天

React的历史与应用

  • 前端应用开发,如Facebook,Instagram,Netflix网页版
  • 移动原生应用开发,如Instagram,Discord,Oculus
  • 结合Electron,进行桌面应用开发

React的设计思路

UI编程痛点

  • UI之间的数据依赖关系,需要手动维护,如果依赖链路长,则会遇到“Callback Hell”。
  • 状态更新,UI不会自动更新,需要手动地调用DOM进行更新。
  • 欠缺基本的代码层面的封装和隔离,代码层面没有组件化。

响应式与转换式

image.png

image.png

响应式编程

image.png

  • 状态更新,UI自动更新。
  • 前端代码组件化,可复用,可封装。
  • 状态之间的互相依赖关系,只需声明即可。

组件化

image.png

  • 组件一个是 原子组件/或组件的组合
  • 组件内部拥有状态,外部不可见
  • 父组件可将状态传入组件内部,来控制子组件的运转。

状态归属问题

组件设计:

  • 组件声明了状态和UI的映射

  • 组件有Props(外部)/State(内部)两种属性

    • Props接受父组件传入的状态
    • State是内部的属性。
  • 可被其他组件组成

React是单向数据流,还是双向数据流?

单向 的,永远是只有父组件给子组件传东西,但这并不代表子组件不能改变父组件的状态。 我们设想这样的情景: 父组件的数据通过props传递给子组件,而子组件更新了props,导致父组件和其他关联组件的数据更新,UI渲染也会随着数据而更新。毫无疑问,这是会导致严重的数据紊乱和不可控制的。因此不能是双向的。

如何解决状态不合理上升的问题?

通过状态管理库,接下来也会讲到。

组件的状态改变后,如何更新DOM?

讲解React实现中会提到。

生命周期

挂载 -> 状态更新 -> 卸载

React(hook)的写法

useState

传入一个初始值,返回一个状态,和set该状态的函数,用户可以通过调用该函数,来实现状态的修改。

下面这段函数用来显示一个计数器,当点击按钮时,计数器的值就会自动增加

import React, {useState} from 'react';
function Example() {
	// 声明一个叫 “count” 的 state 变量。
	const [count, setCount] = useState(0);
    return (
        <div>
       		<p>You clicked {count} times</p>
			<button onClick={() => setCount(count + 1)}>
        		Click me
            </button>
        </div>
    );
}

userEffect

传入一个函数,和一个数组,数组是状态的数组,称作依赖项,该函数在mount时,和依赖项被set的时候会执行。

有“副作用”的函数,要传入useEffect来执行。副作用代表除了单纯的计算之外,还要做其它的一些事情,比如网络请求,更新DOM,localStorage存储数据等。

import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  // 相当于 componentDidMount 和 componentDidUpdate:
  useEffect(() => {
    // 使用浏览器的 API 更新页面标题
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

React的实现

  • JSX 不符合JS标准的语法
  • 返回的JSX改变时,如何更新DOM?
  • State/Props更新时, 要重新触发render函数

Problem1

解决办法也很简单,就是将JSX转换为符合JS语法的

image.png Problem2

返回的JSX本身是类似DOM的一种东西,但不是DOM,DOM操作本身是比较耗费性能的。所以需要将返回的JSX与原来的DOM结构计算一个diff(差别),只更新一个diff,但是这个diff算法本身不能太耗时,尽可能小,尽可能短。

how to diff?

更新次数少 <- 权衡 -> 计算速度快

完美的最小Diff算法,需要 O(n^3) 的复杂度。 而牺牲理论最小Diff,换取时间,得到了 O(n) 复杂度的算法,他是局部最优的。

React状态管理库

核心思想

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

image.png 推荐 redux、 xstate、mobx 、recoil