这是我参与「第五届青训营 」伴学笔记创作活动的第1天
React的历史与应用
历史
- 2010年,Facebook引入的xhp框架出现了组合式组件的思想
- 2011年,Jordan Walke创造了FaxJS
- 支持客服端和服务端渲染
- 响应式:状态改变时UI自动更新
- 更快的渲染速度,更小的代码体积
- 函数式声明组件
- 2012年,Jordan Walke基于FaxJS创造了React
- 当时作者给React的定义是一个JS库而不是框架
应用
- web应用
- 移动端应用
- 桌面端应用(结合Electron)
React的设计思路
UI编程痛点和解决方案
- 状态更新时,需要手动操作DOM进行UI的更新——响应式
- 欠缺基本的代码层面的封装和隔离——组件化
- UI之间的数据依赖关系,需要手动维护,如果依赖链路长,会遇到回调地狱——声明式
组件化设计思路
- 组件声明了状态和UI的映射
- 拥有Props(父组件传入)和State(自身状态)
- 组件可以由其他组件拼装而成
组件化引出的问题
- React是单向数据流还是双向数据流?
- 单向,只能父传子,如果想实现子传父,只能通过父组件传入一个回调函数,由子组件触发该函数实现
- 如何解决状态不合理上升的问题?
- 由于只能父传子,所以当多个组件共享一个状态时要进行状态提升,这个问题可以通过状态管理库解决
- 组件的状态改变后,如果更新DOM?
- 构建虚拟dom,通过diff算法计算出需要更新的dom节点,然后再去更新对应的真实的dom
生命周期
Hooks写法入门
两个基本hook:useState和useEffect
import React, { useState, useEffect } from 'react';
function Example() {
// useState接收一个初始值,返回一个数组,第一个是状态名,第二个是更新状态的方法
const [count, setCount] = useState(0);
// useEffect(如果注入状态,则可类比vue3的watchEffect)中可执行副作用操作(除了单纯的计算外,还要进行其他操作如:网络请求、更新DOM、改变浏览器缓存)
useEffect(() => {
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
使用规则
- 只在最顶层使用Hook:不要在循环和嵌套中使用Hook
- 只在React函数中使用Hook:不要在普通的JS函数中使用Hook
React的实现
问题和解决方案
- JSX不符合JS标准语法——转译
- JSX改变时如何更新DOM——虚拟DOM + Diff算法
- State/Props更新时需要重新触发render函数——同上
React下DOM更新流程
Diff算法——Heuristic O(n) Algorithm
时间复杂度为O(n)——只遍历了一遍DOM树
| 优化后的算法规则 | ||
|---|---|---|
| 情况 | 说明 | 操作 |
| 不同类型的元素 | type由input变为button | 替换 |
| 同类型的DOM元素 | 仅有属性(状态)发生变化 | 更新 |
| 同类型的组件元素 | 组件名相同 | 递归 |