首先祝大家 1024 快乐,然后是最近在看的文档,毕竟最好的 React 学习资料还是官方文档。
第一次读 React 文档是为了会用,
第二次读,是为了学一些不常用的或者新的特性。 像 hook、HOC 等等
现在再读文档,我希望了解之前忽略的部分(如设计理念,规则,定义),完善对它的理解。
React 哲学
如何创建应用?
- 按照“单一功能原则”(即一个组件原则上只负责一个功能)将 UI 拆分组件层级
因为你经常是在向用户展示 JSON 数据模型,所以如果你的模型设计得恰当,UI(或者说组件结构)便会与数据模型一一对应,这是因为 UI 和数据模型都会倾向于遵守相同的信息结构。将 UI 分离为组件,其中每个组件需与数据模型的某部分匹配。
- 编写静态页面,最好将渲染 UI 和添加交互这两个过程分开,并且完全不应该使用 state 构建静态版本。
- 只保留应用所需的可变 state 的最小集合,其他数据均由它们计算产生。
- 确定 state 放置位置
- 添加反向数据流
渲染部分:
- 元素一旦创建,就不能更改。所以要更新页面,只能创建新的元素并渲染。
- React DOM 会将元素和它的子元素与它们之前的状态进行比较,并只会进行必要的更新。
- key 可以帮助 React 识别哪些元素改变了。
组件部分:
概念:UI 可以拆解为独立可复用的代码片段,这些代码片段就是组件。
分类:按声明方式分有函数组件、Class 组件,
行为:组件涉及的一些动作有, 渲染、组合、提取(拆分)
规则:
- React 组件都必须像纯函数一样保护它们的 props 不被更改。想一想,如果组件传入的 props 可以被随意更改,那么对于在多个地方复用的组件来说是灾难性的。
- 相对于 props 的不可更改,state 是私有的,并且完全受控于当前组件。
- 不要直接修改 state
- state 可能是异步的,所以可以给 setState 传入函数
- state 更新会被合并
- 数据流动是单向的,即自上而下。我的理解是父子组件关系像嵌套函数一样,外层取不到内层的参数,所以只能单向流动。
最佳实践:
- 多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去。
- 在 React 中没有“槽”这一概念的限制,你可以将任何东西作为 props 进行传递。
- 在 React 中组件几乎用不到继承,使用组合和 props 足够应对各种情况。
- 如果某个数据可以通过现有 state 和 props 得到,最好不要创建新的 state。
事件系统:
合成事件:即 SyntheticEvent 包装器, 兼容浏览器且提供浏览器原生事件的包装方法。其实例就是在 React 事件中默认传递的参数 e。
diffing 算法:
产生背景:渲染时 render 方法会产生一棵 React 元素树,在 state/props 更新时会产生新树,React 需要基于这两棵树之间的差别来判断如何有效率的更新 UI 以保证当前 UI 与最新的树保持同步。
算法基础理念:
- 两个不同类型的元素会产生出不同的树;
- 开发者可以通过 key prop 来暗示哪些子元素在不同的渲染下能保持稳定;
实现步骤:
从根部开始比较,
- 元素类型不同,则卸载老树元素及子元素,并开始建新树
- 元素类型相同,对比属性,属性值不同更新属性。处理完当前节点,递归子节点
- 组件类型相同,组件实例不变,更新 props,并调用
componentWillReceiveProps()
和componentWillUpdate()
方法。 - 对子节点递归时,如果节点列表中有 key 属性,则对比 key 值来决定是否新建元素。如果没有 key,React 会对新旧两个子元素列表逐个对比,有不同的话会重建元素。此时在向列表头部插入新元素时性能开销最大。
Hook 规则
- 只在顶层函数中调用 hook
- 只在 React 函数中调用 hook
hook 与 Class 组件功能对比:
Class 组件 | Hook |
---|---|
constructor 初始化 state | useState |
ref | useRef |
多个 state 传入 | const [state, setState] = useState({...}) |
shouldComponentUpdate | useCallbackReact.memo |
componentDidMount, componentDidUpdate, componentWillUnmount | useEffect |
getSnapShotBeforeUpdate, componentDidCatch, getDerivedStateFromError | - |
render | 函数组件本身 |
PureComponent | useMemo 多次渲染间缓存计算结果 |
context 深层传递 props | useReducer |