Redux 源码剖析:从入口函数到 createStore

本文将深入剖析 Redux 的源码,从入口函数开始一步步分析每个细节,帮助读者深入理解 Redux 并能够编写出更加高效的 Redux 应用。

入口函数

Redux 的入口函数如下:

------ ----------- ---- ----------------
------ ------------------ ---- -----------------------
------ --------------- ---- --------------------
------ --------------- ---- --------------------
------ ------- ---- ------------

------ -
  ------------
  ----------------
  -------------------
  ----------------
  -------
--

通过 import 关键字引入 createStore、bindActionCreators、combineReducers、applyMiddleware 和 compose 函数,然后通过 export 关键字导出。

createStore 函数

createStore 函数是 Redux 最核心的部分,它的作用是产生一个全局唯一的 store,用于存储应用中所有状态。它的实现如下:

------ ------------- ---- -----------------------
------ ------- ---- ------------------

-------- -------------------- --------------- --------- -
  -- ------- -------------- --- ---------- -- ------ -------- --- ------------ -
    -------- - ---------------
    -------------- - ----------
  -

  -- ------- -------- --- ------------ -
    -- ------- -------- --- ----------- -
      ----- --- --------------- --- -------- -- -- - ------------
    -

    ------ ------------------------------ ----------------
  -

  -- ------- ------- --- ----------- -
    ----- --- --------------- --- ------- -- -- - ------------
  -

  --- -------------- - --------
  --- ------------ - ---------------
  --- ---------------- - ---
  --- ------------- - -----------------
  --- ------------- - ------

  -------- ------------------------------ -
    -- -------------- --- ----------------- -
      ------------- - -------------------------
    -
  -

  -------- ---------- -
    -- --------------- -
      ----- --- ------
        ---- --- --- ---- ---------------- ----- --- ------- -- ---------- - -
          ---- ------- --- ------- -------- --- ----- -- -- --------- - -
          ----- -- ---- ---- --- --- ------- ------- -- ------- -- ---- --- -------
      --
    -

    ------ -------------
  -

  -------- ------------------- -
    -- ------- -------- --- ----------- -
      ----- --- --------------- --- -------- -- -- - ------------
    -

    --- ------------ - -----

    -------------------------------
    -----------------------------

    ------ -------- ------------- -
      -- --------------- -
        -------
      -

      ------------ - ------

      -------------------------------
      ----- ----- - --------------------------------
      --------------------------- ---
      ---------------- - -----
    --
  -

  -------- ---------------- -
    -- ------------------------ -
      ----- --- ------
        -------- ---- -- ----- -------- - -
          ---- ------ ---------- --- ----- ---------
      --
    -

    -- ------- ----------- --- ------------ -
      ----- --- ------
        -------- --- --- ---- -- --------- ------ --------- - -
          ----- --- ---------- - ----------
      --
    -

    -- --------------- -
      ----- --- --------------- --- --- -------- -----------
    -

    --- -
      ------------- - -----
      ------------ - ---------------------------- --------
    - ------- -
      ------------- - ------
    -

    ----- --------- - ----------------- - ---------------
    --- ---- - - -- - - ----------------- ---- -
      ----- -------- - -------------
      -----------
    -

    ------ -------
  -

  -------- --------------------------- -
    -- ------- ----------- --- ----------- -
      ----- --- --------------- --- ----------- -- -- - ------------
    -

    -------------- - ------------

    ---------- ----- -------------- ---
  -

  ---------- ----- -------------- ---

  ------ -
    ---------
    ----------
    ---------
    --------------
  --
-

我们来一步步分解这个函数。

  1. 入参
-------- -------------------- --------------- --------- -

入参有三个:

  • reducer:必选参数,reducer 函数,用于处理应用中所有的 action,返回新的全局 state;
  • preloadedState:可选参数,初始化的 state,如果不传则为 undefined;
  • enhancer:可选参数,一个增强器函数,用于增强 createStore 函数的功能。
  1. 处理 enhancer
-- ------- -------------- --- ---------- -- ------ -------- --- ------------ -
  -------- - ---------------
  -------------- - ----------
-

-- ------- -------- --- ------------ -
  -- ------- -------- --- ----------- -
    ----- --- --------------- --- -------- -- -- - ------------
  -

  ------ ------------------------------ ----------------
-

如果 preloadedState 是函数,并且 enhancer 未定义,则把 preloadedState 赋值给 enhancer,preloadedState 赋值为 undefined。

如果 enhancer 存在,则判断 enhancer 是否是一个函数,如果不是,则抛出错误。如果 enhancer 是一个函数,则把 createStore 传入 enhancer,enhancer 返回的是一个增强版的 createStore 函数。

  1. 处理 reducer
-- ------- ------- --- ----------- -
  ----- --- --------------- --- ------- -- -- - ------------
-

--- -------------- - --------
--- ------------ - ---------------
--- ---------------- - ---
--- ------------- - -----------------
--- ------------- - ------

如果 reducer 不是一个函数,则抛出异常。

currentReducer 存储目前的 reducer;currentState 存储目前的 state;currentListeners 存储当前注册的所有 listener;nextListeners 是 currentListeners 的引用,确保 dispatch 时未注册的 listener 不会遗漏。

  1. 辅助函数
-------- ------------------------------ -
  -- -------------- --- ----------------- -
    ------------- - -------------------------
  -
-

-------- ---------- -
  -- --------------- -
    ----- --- ------
      ---- --- --- ---- ---------------- ----- --- ------- -- ---------- - -
        ---- ------- --- ------- -------- --- ----- -- -- --------- - -
        ----- -- ---- ---- --- --- ------- ------- -- ------- -- ---- --- -------
    --
  -

  ------ -------------
-

-------- ------------------- -
  -- ------- -------- --- ----------- -
    ----- --- --------------- --- -------- -- -- - ------------
  -

  --- ------------ - -----

  -------------------------------
  -----------------------------

  ------ -------- ------------- -
    -- --------------- -
      -------
    -

    ------------ - ------

    -------------------------------
    ----- ----- - --------------------------------
    --------------------------- ---
    ---------------- - -----
  --
-

-------- ---------------- -
  -- ------------------------ -
    ----- --- ------
      -------- ---- -- ----- -------- - - ---- ------ ---------- --- ----- ---------
    --
  -

  -- ------- ----------- --- ------------ -
    ----- --- ------
      -------- --- --- ---- -- --------- ------ --------- - - ----- --- ---------- - ----------
    --
  -

  -- --------------- -
    ----- --- --------------- --- --- -------- -----------
  -

  --- -
    ------------- - -----
    ------------ - ---------------------------- --------
  - ------- -
    ------------- - ------
  -

  ----- --------- - ----------------- - ---------------
  --- ---- - - -- - - ----------------- ---- -
    ----- -------- - -------------
    -----------
  -

  ------ -------
-

-------- --------------------------- -
  -- ------- ----------- --- ----------- -
    ----- --- --------------- --- ----------- -- -- - ------------
  -

  -------------- - ------------

  ---------- ----- -------------- ---
-
  • ensureCanMutateNextListeners:确保 nextListeners 存在,若不存在则将 nextListeners 的引用赋值为 currentListeners 的拷贝。
  • getState:获取当前的 state。
  • subscribe:注册 listener,返回一个函数,用于取消注册。
  • dispatch:根据 action 更新 state 并遍历所有注册的 listener,返回 action。
  • replaceReducer:用于动态替换 reducer,替换后会重新执行一次 INITIAL 操作。

值得注意的是 getState 和 dispatch 这两个函数中通过 isDispatching 变量避免了 reducer 函数的递归调用。

  1. 初始化
---------- ----- -------------- ---

每个 store 一旦初始化完毕,就会自动 dispatch 一个带有 type 属性的 action,type 属性为 "@@redux/INIT"。

  1. 返回值
------ -
  ---------
  ----------
  ---------
  --------------
--

返回一个对象,包含 dispatch、subscribe、getState 和 replaceReducer 属性。

上面的函数使 createStore 成为一个功能强大的函数,能够接收 reducer、preloadedState 和 enhancer 参数,返回一个包含更改应用状态的事件驱动对象。

总结

本文对 Redux 的入口函数和 createStore 进行了详细的分析,其中包括了函数的实现方式和具体细节。最后还给出了合适的示例代码,帮助读者深入理解如何使用 Redux,并能够更好地与其它库结合使用。对于前端开发者来说,深入了解 Redux 的内部实现,将有助于提高应用程序的性能,增强代码质量,提升开发效率。

来源:JavaScript中文网 ,转载请联系管理员! 本文地址:https://www.javascriptcn.com/post/6651ee49d3423812e464c6a5


猜你喜欢

  • Angular 中如何实现集成测试 - 教程

    集成测试是一种将组件连成一个整体测试的方式,它可以检查各个组件之间的交互作用,以及整体系统的行为是否符合期望。在 Angular 开发中,集成测试是非常重要的一环。

    5 个月前
  • Hapi.js 上部署 HTTPS 的方法

    在进行网络开发时,我们经常需要对网站进行安全加密。使用 HTTPS 协议可以实现这种功能。而在 Node.js 中,我们可以使用 Hapi.js 进行 HTTPS 的部署。

    5 个月前
  • Fastify 框架中使用 AJV 校验请求参数的技巧

    在前端的开发过程中,数据交互是一项十分重要的工作。在进行数据交互的过程中,经常需要对请求参数进行校验,以确保数据的正确性和安全性。为了提高开发效率,我们可以使用一些工具来帮助我们进行请求参数的校验。

    5 个月前
  • Redis 应用:实现人物画像分析方案解析

    人物画像分析是指对用户的个人信息进行分析,生成用户的基本情况、兴趣偏好、消费力度等的数据模型。这个模型可以用来指导产品优化、用户分群、推荐系统等方面。实现人物画像分析需要进行大量的数据统计和分析,而 ...

    5 个月前
  • Server-Sent Events:HTML5 时代的 socket 协议?

    在Web应用程序中,实时性是非常必要的,以确保用户获得即时的更新。当谈到实时通信时,WebSocket是一个普及的选择,但对于较简单的场景以及一些特定情况,WebSocket可能过于复杂。

    5 个月前
  • 在 Vue.js 中使用 Lozad.js 实现图片懒加载

    在前端开发中,图片懒加载是一个必不可少的功能。它能够优化页面加载速度,减少带宽的使用,提高用户的体验。在 Vue.js 中,我们可以使用 Lozad.js 库实现图片懒加载的功能,让我们来详细了解一下...

    5 个月前
  • 如何在 Deno 中使用 WebSocket 进行数据实时同步?

    在前端开发中,有时需要实现实时数据同步,以保证多个用户之间的数据共享和协同编辑的能力,而 WebSocket 技术常常被用于解决这个问题。本文将介绍如何在 Deno 中使用 WebSocket 实现数...

    5 个月前
  • SASS 之使用 @while 循环生成多组样式的技巧

    在前端开发中,常常需要生成多组相似的样式,例如一组按钮样式,每个按钮的样式只有颜色稍有差异。这时候使用 @while 循环可以非常方便地生成多组样式。 @while 循环的语法 @while 循环的语...

    5 个月前
  • 如何使用 ECMAScript 2019 中的 Map 和 Set 数据结构

    什么是 Map 和 Set 数据结构 ECMAScript 2019 中引入了两个新的数据结构:Map 和 Set。其中,Map 是一种键值对的集合,其中每个键唯一对应一个值,而 Set 是一种值的集...

    5 个月前
  • ECMAScript 2021 中的优化 nullish coalescing 运算符

    引言 在前端开发中,我们经常需要处理一些数据,而有些数据可能在从后端获取时会返回 null 或 undefined,这会导致编写代码时非常繁琐。为了解决这个问题,JavaScript 引入了 null...

    5 个月前
  • 如何在 TypeScript 中使用 ES6 模块?

    ES6 模块(简称为模块)是指 ES6 新增的一种模块化编程的规范,它允许将程序划分为不同的几个文件,每个文件被看作是一个模块,并且可以按需导出和导入模块中的内容。

    5 个月前
  • Angular 中如何实现单元测试 - 教程

    单元测试是一种测试方法,它在隔离的环境中测试应用程序的每个单独部分。在 Angular 项目中,单元测试可以帮助开发人员更快地找到和修复错误。 在本文中,我们将讨论 Angular 中的单元测试如何实...

    5 个月前
  • 如何在 Fastify 框架中使用 OpenAPI 规范

    前言 Fastify 是一个快速且低开销的 Node.js Web 框架,提供了非常出色的性能。OpenAPI 规范是一个用于定义 RESTful API 的标准,它可以让你更方便地管理你的 API,...

    5 个月前
  • 使用 Chai 测试框架进行 HTTP API 测试

    在前端开发过程中,HTTP API 测试是必不可少的环节。如果没有良好的测试框架,测试工作将变得非常困难和不可靠。Chai 是一个流行的 JavaScript 测试框架,它提供了丰富的断言库和易于使用...

    5 个月前
  • Redis 应用:实现在线聊天方案解析

    在现代化的 Web 应用中,实时通信已经成为了一个非常重要的需求。人们通过聊天系统来进行沟通,交流信息。要实现这样的功能,选择一种适合的技术是必要的。Redis 作为流行的内存数据库,已经被广泛应用在...

    5 个月前
  • 在 Webpack 中使用 extract-text-webpack-plugin 插件分离 CSS

    引言 在前端开发中,CSS 是必不可少的一部分。随着项目变得越来越大,CSS 文件也会变得越来越庞大,这会导致页面加载缓慢,影响用户体验。为了减少加载时间,我们通常会考虑将 CSS 文件进行分离。

    5 个月前
  • 使用 ESLint 规范 Vue.js 项目中的 JavaScript 代码

    什么是 ESLint? ESLint 是一款插件化的 JavaScript 代码检查工具,可以帮助我们检查代码语法、优化性能、统一团队代码风格等。 在 Vue.js 项目中使用 ESLint,可以有效...

    5 个月前
  • 详解 Kubernetes 应用程序比较常见的监控工具

    Kubernetes 是一个开源的容器编排系统,用于自动化部署、扩展和管理应用程序容器。在 Kubernetes 中,我们可以很方便地管理应用程序的运行状态,但是如何监控和管理应用程序的性能和健康状态...

    5 个月前
  • 如何使用 Flexbox 实现响应式菜单设计?

    随着移动设备的日益普及,响应式设计已经成为网站设计的重要组成部分。在移动设备中,菜单是网站最重要的组成部分之一。在这篇文章中,我们将使用 Flexbox 实现一个响应式菜单设计。

    5 个月前
  • TypeScript 中的 interface 与 class 有何不同?

    在 TypeScript 中,interface 和 class 是两个非常重要的概念。它们都用于描述类型,并且在编写可维护、可扩展的代码时非常有用。然而,它们之间还是存在一些区别的。

    5 个月前

相关推荐

    暂无文章