React Hooks 全解:原理、API 与应用场景

目录

重点总结

[1. 什么是 Hooks?为什么要用它?](#1. 什么是 Hooks?为什么要用它?)

[2. 基础 Hooks(日常开发使用率 90%)](#2. 基础 Hooks(日常开发使用率 90%))

[2.1 useState](#2.1 useState)

[2.2 useEffect](#2.2 useEffect)

[2.3 useContext](#2.3 useContext)

[3. 进阶 Hooks(性能优化与复杂逻辑)](#3. 进阶 Hooks(性能优化与复杂逻辑))

[3.1 useReducer](#3.1 useReducer)

[3.2 useCallback](#3.2 useCallback)

[3.3 useMemo](#3.3 useMemo)

[3.4 useRef](#3.4 useRef)

[4. 只有在特定场景才用的 Hooks](#4. 只有在特定场景才用的 Hooks)

[4.1 useLayoutEffect](#4.1 useLayoutEffect)

[4.2 useImperativeHandle](#4.2 useImperativeHandle)

[4.3 useDebugValue](#4.3 useDebugValue)

[5. React 18+ 新增 Hooks(并发模式相关)](#5. React 18+ 新增 Hooks(并发模式相关))

[5.1 useId](#5.1 useId)

[5.2 useTransition](#5.2 useTransition)

[5.3 useDeferredValue](#5.3 useDeferredValue)

[6. 自定义 Hook (Custom Hook)](#6. 自定义 Hook (Custom Hook))

重点总结

  1. 定义:Hooks 是 React 16.8 引入的,解决了 Class 组件逻辑复用难、this 指向混乱等问题,让函数组件拥有了状态和生命周期。

  2. 核心三剑客:重点介绍 useState(状态)、useEffect(副作用)、useContext(跨组件通信)。

  3. 性能优化:提到 useMemo(缓存值)和 useCallback(缓存函数),并说明它们是为了避免不必要的渲染和计算。

  4. 引用与操作:提到 useRef 用于访问 DOM 或存储不触发渲染的变量。

  5. 高阶场景:简单带过 useReducer(复杂状态)和 useLayoutEffect(同步 DOM 测量)。

  6. React 18:如果想加分,提一下 useTransition 用于并发模式下的渲染优化。

1. 什么是 Hooks?为什么要用它?

定义:Hooks 是 React 16.8 引入的新特性,允许你在不编写 Class(类)组件的情况下,使用 State(状态)和其他 React 特性。

解决了什么问题(面试必问)

  1. 复用逻辑难:在 Class 组件中,复用逻辑通常依靠 HOC(高阶组件)或 Render Props,导致组件嵌套层级过深(Wrapper Hell)。Hooks 可以通过"自定义 Hook"完美解决。

  2. 组件复杂难以维护:Class 组件迫使我们将逻辑分散在 componentDidMount、componentDidUpdate 等生命周期中(例如:同一个定时器的启动和销毁被拆分)。Hooks 将相关逻辑聚合在一起。

  3. Class 的 this 指向困扰:不需要再绑定 this。

两个铁律

  1. 只能在函数组件的最顶层调用(不要在循环、条件或嵌套函数中调用)。

  2. 只能在 React 函数组件自定义 Hook 中调用。


2. 基础 Hooks(日常开发使用率 90%)

2.1 useState

  • 作用:在函数组件中声明和管理状态。

  • API:const [state, setState] = useState(initialState);

  • 场景

    • 简单的 UI 状态(如:模态框的显隐、输入框的值、计数器)。
  • 面试考点

    • setState 是异步的(批处理)。

    • 如果新状态依赖于旧状态,推荐使用函数式更新:setCount(prev => prev + 1)。

2.2 useEffect

  • 作用:处理副作用(Side Effects)。相当于 componentDidMount、componentDidUpdate 和 componentWillUnmount 的集合。

  • API:useEffect(setup, dependencies?)

  • 场景

    • 数据获取(API 请求)。

    • 订阅事件(如 addEventListener)。

    • 手动修改 DOM(如 document.title)。

  • 依赖项数组(重要)

    • \]:只在组件挂载时执行一次(类似 componentDidMount)。

    • 不传:每次渲染都执行(慎用)。

  • 清理函数:return 一个函数用于清除副作用(如清除定时器),类似 componentWillUnmount。

2.3 useContext

  • 作用:接收 Context 对象,实现跨层级组件通信,避免"Props Drilling"(属性层层传递)。

  • API:const value = useContext(MyContext);

  • 场景

    • 全局主题(Theme)。

    • 用户登录状态(Auth)。

    • 国际化配置(i18n)。


3. 进阶 Hooks(性能优化与复杂逻辑)

3.1 useReducer

  • 作用:useState 的替代方案,用于管理复杂的状态逻辑。

  • API:const [state, dispatch] = useReducer(reducer, initialState);

  • 场景

    • 状态逻辑复杂,包含多个子值(如表单对象)。

    • 下一个状态依赖于之前的状态。

    • 业务场景:购物车逻辑(添加、删除、更新数量)、复杂的表单验证。

  • 理解:如果你用过 Redux,它就是 React 内置的迷你 Redux。

3.2 useCallback

  • 作用 :缓存函数引用

  • API:const memoizedCallback = useCallback(fn, dependencies);

  • 场景

    • 将函数作为 props 传递给经过 React.memo 优化的子组件时,防止因父组件渲染导致函数引用变化,进而导致子组件不必要的重新渲染。
  • 注意:不要滥用,只有在配合 React.memo 或作为其他 Hook 的依赖时才有意义。

3.3 useMemo

  • 作用 :缓存计算结果

  • API:const cachedValue = useMemo(calculateValue, dependencies);

  • 场景

    • 昂贵的计算:例如处理大数组的过滤、排序。

    • 避免在每次渲染时都进行高开销的计算。

  • 区别:useCallback 缓存的是函数本身,useMemo 缓存的是函数的返回值。

3.4 useRef

  • 作用

    • 访问 DOM 节点。

    • 保存一个可变的变量,改变它不会触发组件重新渲染

  • API:const refContainer = useRef(initialValue);

  • 场景

    • 让输入框自动聚焦 (inputRef.current.focus())。

    • 存储定时器的 ID(以便清理)。

    • 记录上一次的 Props 或 State(实现 usePrevious)。


4. 只有在特定场景才用的 Hooks

4.1 useLayoutEffect

  • 作用 :与 useEffect 类似,但它是在 DOM 变更之后、浏览器绘制之前 同步执行的。

  • 场景

    • 你需要测量 DOM 元素的尺寸(如宽、高),并根据测量结果立即修改 DOM。

    • 目的:防止页面闪烁(FOUC)。如果是为了读取布局信息,用它;如果是纯数据请求,用 useEffect。

4.2 useImperativeHandle

  • 作用:自定义暴露给父组件的实例值(通常配合 forwardRef 使用)。

  • 场景

    • 父组件需要调用子组件内部的方法(例如:父组件点击按钮,让子组件的 input 聚焦,或者重置子组件的表单)。

    • 原则:尽量少用,React 推荐数据流驱动,而不是命令式调用。

4.3 useDebugValue

  • 作用:在 React DevTools 中显示自定义 Hook 的标签。

  • 场景:开发自定义 Hook 库时使用,方便调试。


5. React 18+ 新增 Hooks(并发模式相关)

5.1 useId

  • 作用:生成唯一的 ID。

  • 场景

    • 用于无障碍属性 aria-describedby。

    • 服务端渲染(SSR)时,确保客户端和服务端生成的 ID 一致。

5.2 useTransition

  • 作用:将某些状态更新标记为"不紧急"(Transition)。

  • API:const [isPending, startTransition] = useTransition();

  • 场景

    • 输入框搜索:用户输入是紧急的(如果不响应会觉得卡),但下方的列表筛选渲染是不紧急的。可以用 startTransition 包裹列表的更新,保证输入框流畅。

5.3 useDeferredValue

  • 作用:延迟更新某个值(类似防抖/节流,但由 React 自动控制)。

  • 场景

    • 接收一个高频变化的值(如输入框的 value),返回一个延迟更新的版本,用于驱动耗时的列表渲染。

6. 自定义 Hook (Custom Hook)

这是 React Hooks 最强大的地方。

  • 定义:就是一个普通的函数,但名字必须以 use 开头,且内部调用了其他 Hooks。

  • 作用:提取组件逻辑,实现复用。

  • 示例

    javascript 复制代码
    // 封装一个获取窗口大小的 Hook
    function useWindowSize() {
      const [size, setSize] = useState([window.innerWidth, window.innerHeight]);
      
      useEffect(() => {
        const handleResize = () => setSize([window.innerWidth, window.innerHeight]);
        window.addEventListener('resize', handleResize);
        return () => window.removeEventListener('resize', handleResize);
      }, []);
      
      return size;
    }
相关推荐
袋鱼不重16 小时前
保姆级教程:让 Cursor 编辑器突破地区限制,正常调用大模型(附配置 + 截图)
前端·后端·cursor
bieao16 小时前
Vite+Antd+Micro-app中iframe模式下样式闪烁的问题
前端
zhouzhouya16 小时前
码上星辰,人间烟火:我的2025
前端·程序员·代码规范
江湖yi山人16 小时前
生产环境的log,上传到开发者的本地服务器
javascript·python
彭涛36116 小时前
什么是MessageChannel
前端
嘉琪00116 小时前
provide 和 inject的理解?
前端·javascript·vue.js
匆叔16 小时前
ESLint,前端项目CTRL+S,自动保存格式化文档,超细
前端
满天星辰16 小时前
Vue3响应式API-reactive的原理
前端·vue.js
XiaoYu200216 小时前
第10章 SSE魔改
前端·webassembly