惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The GitHub Blog
The GitHub Blog
雷峰网
雷峰网
小众软件
小众软件
博客园 - 【当耐特】
J
Java Code Geeks
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Hugging Face - Blog
Hugging Face - Blog
腾讯CDC
Engineering at Meta
Engineering at Meta
aimingoo的专栏
aimingoo的专栏
A
About on SuperTechFans
H
Help Net Security
博客园_首页
P
Proofpoint News Feed
GbyAI
GbyAI
大猫的无限游戏
大猫的无限游戏
N
Netflix TechBlog - Medium
爱范儿
爱范儿
MyScale Blog
MyScale Blog
Blog — PlanetScale
Blog — PlanetScale
The Cloudflare Blog
MongoDB | Blog
MongoDB | Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Google DeepMind News
Google DeepMind News

蚊子的前端博客

微说 | 有的人觉得只要不考XX,一定能考好!-蚊子的前端博客 微说 | 春天来了-蚊子的前端博客 明天和意外不知道哪个先来-蚊子的前端博客 微说 | 既然错过了路口,就及时止损,重新规划路线上路-蚊子的前端博客 微说 | 2025年的出生人口数是792万-蚊子的前端博客 微说 | 工作年终总结,让写对接的接口的数量?-蚊子的前端博客 微说 | 温家宝:没有政治体制改革的成功 经济体制改革不可能进行到底-蚊子的前端博客 微说 | 违法犯罪了该不该被禁言?-蚊子的前端博客 微说 | 不明白为什么在推荐去俄罗斯旅游-蚊子的前端博客 微说 | 易中天论骗子-蚊子的前端博客 微说 | 一场大风吹散了秋天-蚊子的前端博客 微说 | 既要、又要、还要、更要!-蚊子的前端博客 又是一年的国庆雨季-蚊子的前端博客 微说 | 预估下2025年的出生人口数据-蚊子的前端博客 微说 | 可惜了我那些小时候的书本-蚊子的前端博客 微说 | 牛马有的是,驴不够了!-蚊子的前端博客 微说 | 能否有一条非户口也能高考的路-蚊子的前端博客 微说 | 小聊中医-蚊子的前端博客 微说 | 将要制作的一款新产品-蚊子的前端博客 微说 | 做人要有信-蚊子的前端博客 微说 | 好一个正义联盟-蚊子的前端博客 微说 | 都是见过吃过的主儿-蚊子的前端博客 微说 | 追求8小时工作制有错吗?-蚊子的前端博客 微说 | 如果尖锐的批评完全消失-蚊子的前端博客 微说 | 很好!-蚊子的前端博客 微说 | 封禁用户可以,但要告知具体原因-蚊子的前端博客 微说 | 面朝大海,春暖花开-蚊子的前端博客 微说 | 程序员的悲哀是什么?-蚊子的前端博客 微说 | 2025年出生人口的预测-蚊子的前端博客 前端在 LiveKit 中如何获取所有的参与者-蚊子的前端博客
React18 源码解析之 useReducer 的原理-蚊子的前端博客
author · 2023-07-12 · via 蚊子的前端博客

我们解析的源码是 React18.1.0 版本,请注意版本号。React 源码学习的 GitHub 仓库地址:https://github.com/wenzi0github/react

在浏览该文章前,请一定要先看文章React18 源码解析之 useState 的原理。不过若您看完关于 useState() 的文章后,其实 useReducer 的源码也就不用讲了。

1. useReducer() 的用法 #

我们先来看下 useReducer 的用法。

useState() 实际上相当于 useReducer() 的简化版(或者定制版)。我们已经提前约定好了 dispatch()(即 setState())内部的功能。但若执行的操作比较复杂,useState() 无法满足我们的需要时,可以通过 useReducer() 来可以自定义 reducer,来实现相对复杂的状态变更。

然后传给 useReducer()的第 1 个参数(第 2 个参数是 state 的初始值)。

useReducer() 的 hook 接收两个参数:

  • reducer: 执行 dispatch() 时的具体操作,该回调方法有两个参数,第 1 个是当前的状态,第 2 个是 dispatch()传入的数据;返回值即为要更新的状态;
  • initialState: 状态的初始值;

先来看一个 useReducer() 的简单的例子:

// 设置初始值
const initialState = { count: 0 };

// 自定义一个 reducer
function reducer(state, action) {
  switch (action.type) {
    case 'increment': {
      return { count: state.count + 1 };
    }
    case 'decrement': {
      return { count: state.count - 1 };
    }
    default: {
      return state;
    }
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
    </>
  );
}

useReducer 的返回值是一个数组,数组中包含两个元素:

  • state:当前的状态值。
  • dispatch:一个用于触发状态更新的函数。当 dispatch 被调用时,会触发 reducer 函数,并传递当前状态和 action 作为参数。

按照习惯,我们一般约定,action 参数中通常有两个属性:

  • type: 当前操作的类型;
  • payload: 传入的数据,但不是必须的;

与 useState 相比,useReducer 的优点在于它可以管理更加复杂的状态,并且状态更新更加可控、可预测。同时,若多个 state 的变化过程一样的,还可以共用 reducer。

2. mountReducer() 的源码解析 #

mountReducer()跟 mountState() 的代码几乎一样:

mountReducer 与 mountState 的对比

可以看到 mountState() 中是指定了 reducer 的,而 mountReducer() 是开发者自行传入的。

该 hook 的挂载过程,可以参考:hook 的初始挂载 - React18 源码解析之 useState 的原理。(偷个懒)

3. updateReducer() 的源码解析 #

updateReducer()在 React 内部被调用过程中,若 useState() 的操作,则会指定 reducer 为 basicStateReducer。而若是 useReducer() 的操作,则会接收开发者传入的 reducer。

该方法的源码,可以参考:updateReducer - React18 源码解析之 useState 的原理

4. 总结 #

useState() 和 useReducer() 中大部分的代码都是复用的,因此跟之前的文章内容比较重复。