Redux 源码分析及实现原理解析

阅读时长 13 分钟读完

前言

Redux 是一个流行的前端状态管理库,它通过单向数据流的设计,让前端的数据流变得简单、可控、易于维护。本文将介绍 Redux 的源码分析,包括 Redux 运行的流程和原理解析,以及如何实现一个简单的 Redux 库。

Redux 运行流程

Redux 的运行流程可以归纳为三个步骤:定义状态、定义修改状态的行为和管理状态的改变。下面一一介绍:

1. 定义状态

Redux 的 state 可以理解为前端应用程序的状态树,它包含了所有组件所需要的数据。因为 Redux 是一个单向数据流的设计,所以 state 是只读的。我们可以通过 store.getState() 方法来获取当前状态。

2. 定义修改状态的行为

在 Redux 中,修改状态的行为被称为 Action,它是一个简单的 JavaScript 对象,包含两个属性:type 和 payload(可选项)。其中 type 用于描述这个 Action 的类型,payload 用于传递需要修改的数据。我们可以通过 store.dispatch() 方法来将一个 Action 分发给 Redux。

3. 管理状态的改变

在 Redux 中,状态的改变被称为 Reducer。Reducer 是一个纯函数,它接收当前状态和 Action 作为参数,并返回一个新的状态。Reducer 应该是无副作用的,它只处理传入的参数,不会改变任何外部的状态。Reducer 是通过 store.subscribe() 方法来注册的。

Redux 实现原理解析

了解了 Redux 的运行流程,下面我们来具体分析一下 Redux 的实现原理。

Store

在 Redux 中,Store 是 Redux 的核心部件。它包含了整个应用程序的状态树,并对外提供了以下几个 API:

  • getState():获取当前的状态树;
  • dispatch(action):分发一个 Action,更新状态树;
  • subscribe(listener):注册一个状态改变监听器。

我们来看一下 Store 的实现。

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

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

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

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

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

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

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

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

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

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

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

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

可以看到,Store 有三个关键变量:currentReducer、currentState 和 currentListeners。其中 currentReducer 用于记录当前使用的 Reducer,currentState 用于记录当前的状态树,currentListeners 用于记录注册的监听器。

Store 的 subscribe 方法实际上是一个观察者模式的实现,它将注册的监听器保存在 currentListeners 数组中。每当 dispatch 发生时,它会通过 nextListeners 获取到注册的最新的监听器,然后更新 currentListeners 数组,并遍历监听器数组以执行相应的监听器方法。

dispatch 方法非常重要,它负责处理 Action,并且调用 Reducer 方法来更新状态树。当 dispatch 方法执行时,如果有其他 dispatch 函数正在执行,则会抛出一个异常,因为一个 Reducer 只能输出一个状态树。

Reducers

在 Redux 中,Reducers 是一个纯函数,它负责处理 Action,并返回新的状态树。Reducers 必须是一个纯函数,没有任何副作用。一个纯函数的定义是:同样的输入(Action 和当前状态树),返回的结果必须一致,不会有任何副作用。

Reducers 通常用 switch 语句对 Action 进行处理,例如:

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

我们来看一下 Reducer 的实现。

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

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

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

可以看到,combineReducers 函数将多个 Reducer 合并为一个大的 Reducer,它以一个代表整个应用程序状态树的对象作为参数。在 combination 函数的内部,通过遍历所有的 Reducer,获取每个 Reducer 的名称和对应的函数。然后循环调用每个 Reducer 来获取新的状态值,并记录下每个 Reducer 是否有改变 state 的值。最后,根据 hasChanged 的值来决定返回新的 state 还是旧的 state。

Actions

在 Redux 中,Actions 代表着用户的行为。它是一个简单的 JavaScript 对象,包含两个属性:type 和 payload(可选项)。type 属性用于描述这个 Action 的类型,payload 是一个可选项,用于传递需要修改的数据。

我们来看一下如何定义一个 Action。

在实际使用中,我们通常会将 Action 定义为一个函数。

Middleware

在 Redux 中,Middleware 是指一个函数,它接收 store 的 dispatch 和 getState 方法,并返回一个函数,该函数接收下一个 Middleware 的 dispatch 和 getState 方法,并返回一个新的 dispatch 函数。Middleware 可以使用这个返回的 dispatch 函数来修改 Action,来阻止 Action,来执行异步任务等,最后通过调用 next 来将 Action 传递下去。

Middleware 通常在一个编写应用程序时被用到,它能够拦截 action 分发,执行额外的处理,然后将 action 发送到 reducers 进行处理。

我们来看一下如何编写一个 Middleware。

在上面的例子中,loggerMiddleware 接收 store,并返回一个函数,该函数接收 next 和 action,最后返回一个新的 dispatch 函数。该函数当 dispatch 应用一个 action 时,在 console 上打印 action 和新的 state。

完整的 Redux 实现

截止到目前为止,我们已经了解了 Redux 的核心部件,下面我们将看一下如何使用它们来构建一个完整的 Redux 应用程序。

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

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

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

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

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

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

在上面的例子中,我们定义了 reducer 和 store,然后定义了两个监听事件,分别对应增加和减少。在事件的回调函数中,我们通过 store.dispatch() 方法分发了一个 Action,触发了 Reducer 的调用,最后通过 store.subscribe() 注册的 render 方法来更新 UI。

结语

本文介绍了 Redux 的源码分析和实现原理,包括:Store、Reducers、Actions 和 Middleware。通过本文的阅读,相信读者已经了解了 Redux 的实现原理,以及如何使用它构建一个完整的 Redux 应用程序。最后,希望本文对读者有所帮助。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/6781fb85935627c900f2577d

纠错
反馈