前端学习-React Hook(钩子)
一.概述
1.什么是 Hook
hook(钩子)是一种特殊的消息处理机制,它可以监视系统或者进程中的各种事件消息,截获发往目标窗口的消息并进行处理。
1.1 Hook 例子
- 函数记录日志、节流、缓存
- Windows 窗口消息拦截
- 键盘事件拦截(木马和外挂)
- 流量识别分析
1.2 React Hook
我们可以通过 Hook 把需要的状态、副作用方法 “钩” 进来,放到函数内部使用。让原来呆板的 React 函数拥有状态和生命周期。
2. Hook 出现的意义
函数一等公民 - 函数式编程
关注状态变化 - 响应式编程
关注分离,逻辑复用
2.1 没有真正使用到 Class 的特性
- 继承:render 方法无法继承
- 类方法:实例化和命令式调用场景少
2.2 在组件之间逻辑难复用
高阶组件问题:
- 实现和使用比较麻烦。
- 组件会有额外节点,多个高阶组件需要层层嵌套。
2.3 生命周期逻辑难维护
- 同一类逻辑分散在不同生命周期
- 同一个生命周期中包含不同逻辑
2.4 Hook 不擅长的地方
- 组件实例、异步闭包应用、非幂调用等场景。
- 在实际开发过程中,需要根据实际的场景来选择 Class 或 Hook。
二.基础 Hook API
1. useState —— 让函数拥有内部状态
const [state, setState] = useState(initialState);
- 调用返回一个数组,分别是 state(状态)和 更新 state 的函数。
- 在初始渲染期间,返回的 state 与传入的 initialState 相同。
- 调用 setState 时可传入新的 state 值,也可以传入更新 state 的回调方法。
2. useEffect —— 让函数可以执行副作用
useEffect(didUpdate, dependencies);
- 可以让你在函数组件中执行副作用操作。
- 该 Hook 接收一个包含命令式、且可能有副作用代码的函数(didUpdate)。
2.1 函数副作用 和 纯函数
- 函数副作用:对主调函数产生额外影响。如修改全局变量(函数外的变量),修改参数或改变外部存储。
- 纯函数:函数与外界交换数据只有一个唯一渠道:参数和返回值。
有副作用的函数都不是纯函数。
2.2 条件执行
- 传空数组 []:仅函数第一次执行时执行第一个回调方法。
- 不穿:函数每次执行时都会重新执行第一个回调方法。
- 传入依赖 [a, b, ...]:函数每次执行时,如果依赖有变化,则重新执行第一个回调方法。
// 仅第一次执行
useEffect(didUpdate, []);
// 每次执行
useEffect(didUpdate);
// a 或 b 有变化时执行
useEffect(didUpdate, [a, b]);
2.3 回调方法返回清理函数
useEffect(function didUpdate(){
// 做更新工作
// 返回清除效果
return function(){
// 清除工作
}
}, []);
仅在 依赖变化 和 销毁前执行。
2.4 useEffect vs useLayoutEffect
- 在 DOM 修改后且浏览器渲染之前。
- useLayoutEffect 比 useEffect 更早执行。
- useEffect 是异步执行,不阻塞渲染;useLayoutEffect 是同步执行,会阻塞渲染。
3. useContext —— 让函数可以接收 context 对象
const value = useContext(MyContext);
- React.createContext 创建 Context
- Context.Provider 提供 value
- useContext 使用 value(类似 Context.Consumer)
3.1 React Context Api 的三大概念
React.createContext()
// React.createContext 这个方法用来创建 context 对象
// 并包含 Provider,Consumer两个组件 <Provider />, <Consumer />
const {Provider, Consumer} = React.createContext();
Provider
// 数据的生产者,通过 value 属性接收存储的公共状态,来传递给子组件或后代组件
<Provider value={/* some value */}>
Consumer
// 数据的消费者,通过订阅 Provider 传入的 context 的值,来实时更新当前组件的状态
<Consumer>
{value => /* 根据上下文值呈现内容 */}
</Consumer>
4.Hook 规则
- 规则一:只在 React 函数中调用 Hook
- 规则二:只在最顶层使用 Hook
记忆单元格:类似数组方式存储 Hooks List,通过调用顺序(Index)获取。
三.自定义 Hook
1.自定义 Hook 规则
- 规则一:自定义 Hook 必须以 “use” 开头
- 规则二:不同组件使用相同 Hook 不共享 state
- 规则三:同一个组件每次调用 Hook,它都会获取 独立的 state
四.扩展 API
1. useReducer —— 独立状态管理
const [state, dispatch] = useReducer(reducer, initialArg, init);
- 是 useState 的替代方案,提供在函数外部管理 state。
- 第一个 reducer 参数是 state 的处理函数(确保是纯函数)。
- 第二个参数(必选)和第三个参数(可选),负责设置 state 的初始值。
- 调用 dispatch 将通过 reducer 来获取并设置新的 state。
state:状态;dispatch:触发状态更新;reducer:状态修改器。
2. useCallback —— 缓存函数
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
执行后返回一个被缓存的(memoized)回调函数,常用于性能优化。
3. useMemo —— 缓存计算结果
const memoizedValue = useMemo(
() => computeExpensiveValue(a, b),
[a, b]
);
- 第一个函数参数会在渲染期间执行。
- 第二个参数依赖列表是执行条件,和 useEffect 一致。
4. 缓存比较
| 场景 | API | 类型 |
| Class | shouldComponentUpdate | Class 组件是否重新 render |
| React.PureComponent | Class 基类,浅比较 props 和 state | |
| Hook | React.memo | Hook 高阶组件,浅比较 props |
| React.useMemo | Hook,缓存计算结果 | |
| React.useCallback | Hook,缓存函数 |
React.memo > React.useCallback > React.useMemo
- 优先做纯函数组件优化。
- 再缓存传入的方法。
- 最后做精细化的渲染缓存控制。
注意:React 的 vDom Diff 已经帮我们避免了大部分 DOM 渲染了。以上这些缓存优化手段是防止重新进行 React render。
5. useRef —— 函数储存容器
const refContainer = useRef(initialValue);
- useRef 调用后返回一个有 current 属性的 “盒子”。
- 给组件的 ref 传递后,current 被设置为组件实例。
- current 可以存储任何对象。
6. useImperativeHandle —— 实例化的“曲线救国”
useImperativeHandle(ref, createHandle, [deps]);
-
useImperativeHandle 可以让你在使用 ref 时自定义暴露给父组件的实例值。在大多数情况下,应当避免使用 ref 这样的命令式代码。useImperativeHandle 应当与 forwardRef 一起使用。
-
React.forwardRef:子组件通过React.forwardRef来创建,可以将ref传递到内部的节点或组件,进而实现跨层级的引用。
本文章整理上课 ppt,仅供学习使用。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)