这是我参与「第四届青训营 」笔记创作活动的的第14天
React的历史与应用
- 前端应用开发,如Facebook,Instagram,Netflix网页版
- 移动原生应用开发,如Instagram,Discord,Oculus
- 结合Electron,进行桌面应用开发
React的设计思路
UI编程痛点
- UI之间的数据依赖关系,需要手动维护,如果依赖链路长,则会遇到“Callback Hell”。
- 状态更新,UI不会自动更新,需要手动地调用DOM进行更新。
- 欠缺基本的代码层面的封装和隔离,代码层面没有组件化。
响应式与转换式
响应式编程
- 状态更新,UI自动更新。
- 前端代码组件化,可复用,可封装。
- 状态之间的互相依赖关系,只需声明即可。
组件化
- 组件一个是 原子组件/或组件的组合
- 组件内部拥有状态,外部不可见
- 父组件可将状态传入组件内部,来控制子组件的运转。
状态归属问题
组件设计:
-
组件声明了状态和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语法的
Problem2
返回的JSX本身是类似DOM的一种东西,但不是DOM,DOM操作本身是比较耗费性能的。所以需要将返回的JSX与原来的DOM结构计算一个diff(差别),只更新一个diff,但是这个diff算法本身不能太耗时,尽可能小,尽可能短。
how to diff?
更新次数少 <- 权衡 -> 计算速度快
完美的最小Diff算法,需要 O(n^3) 的复杂度。 而牺牲理论最小Diff,换取时间,得到了 O(n) 复杂度的算法,他是局部最优的。
React状态管理库
核心思想
将状态抽离到UI外部进行统一管理
推荐
redux、 xstate、mobx 、recoil