React Hooks 核心原理与实战
Tags: 前端源码
创建时间: May 24, 2022
评星: ⭐️⭐️⭐️⭐️⭐️
03|内置 Hooks(1):如何保存组件状态和使用生命周期?
useState原则
state
中永远不要保存可以通过计算得到的值。
React Hooks 四种执行时机
useEffect
让我们能够在下面四种时机去执行一个回调函数产生副作用:
- 每次
render
后执行:不提供第二个依赖项参数。比如useEffect(() => {})
- 仅第一次
render
后执行:提供一个空数组作为依赖项。比如useEffect(() => {}, [])
- 第一次以及依赖项发生变化后执行:提供依赖项数组。比如
useEffect(() => {}, [deps])
- 组件
unmount
后执行:返回一个回调函数。比如useEffect() => { return () => {} }, [])
Hooks 的使用规则
Hooks
只能在函数组件的顶级作用域使用所谓顶层作用域,就是
Hooks
不能在循环、条件判断或者嵌套函数内执行,而必须是在顶层。同时Hooks
在组件的多次渲染之间,必须按顺序被执行。Hooks
只能在函数组件或者其它Hooks
中使用
04|内置 Hooks(2):为什么要避免重复定义回调函数?
useCallback:缓存回调函数
1 | function Counter() { |
接收了 handleIncrement
,并作为一个属性。如果每次都是一个新的,那么这个 React
就会认为这个组件的 props
发生了变化,从而必须重新渲染。因此,我们需要做到的是:只有当 count
发生变化时,我们才需要重新定一个回调函数。而这正是 useCallback
这个 Hook
的作用。
1 | import React, { useState, useCallback } from 'react'; |
useMemo:缓存计算的结果
1 | let usersToShow = null; |
这个场景应该很容易理解:如果某个数据是通过其它数据计算得到的,那么只有当用到的数据,也就是依赖的数据发生变化的时候,才应该需要重新计算。
1 | //... |
缓存上一次的计算结果,useMemo 可以避免子组件重复渲染。
useRef:在多次渲染之间共享数据
useRef 看作是在函数组件之外创建的一个容器空间,用于共享变量。
1 |
|
保存某个 DOM 节点的引用
1 | function TextInputWithFocusButton() { |
useContext:定义全局状态
要跨层次,或者同层的组件之间要进行数据的共享,React 提供了 Context 这样一个机制,能够让所有在某个组件开始的组件树上创建一个 Context。这样这个组件树上的所有组件,就都能访问和修改这个 Context 了。那么在函数组件里,我们就可以使用 useContext 这样一个 Hook 来管理 Context。
08|复杂状态处理:如何保证状态一致性?
原则一:保证状态最小化
1 |
|
🔥 核心原则,如果能通过计算得到结果,就不要保存在state中。这样需要手动维护数据一致性,增加复杂度。
原则二: 避免中间状态,确保唯一数据源
10|函数组件设计模式:如何应对复杂条件渲染场景?
容器模式:实现按条件执行 Hooks
所谓容器模式,是将判断逻辑放在容器内部,从而避免在判断逻辑中写 hooks
1 | // 定义一个容器组件用于封装真正的 UserInfoModal |
同理,在自定义hooks内部,判断是否处理
1 | function useUser(id) { |
使用 render props 模式重用 UI 逻辑
render props
就是把一个 render
函数作为属性传递给某个组件,由这个组件去执行这个函数从而 render
实际的内容。
1 | import { useState, useCallback } from "react"; |
一个showMore的例子,实现UI的重用
1 | // ListWithMore.jsx |
1 | // ListWithMoreExample.jsx 这里用一个示例数据 |