Redux 源码解析:最核心的 createStore 函数如何运作?

如果你是一名前端开发者,那么你一定对 Redux 这个状态管理库不会陌生。Redux 作为一个轻量级的状态容器,可以帮助我们更方便地管理应用程序的状态,从而提高应用程序的可维护性和可扩展性。Redux 最核心的函数之一就是 createStore,本文将详细解析 createStore 函数的源码实现。

createStore 的作用

createStore 函数是 Redux 中最重要的函数之一,它的作用是创建一个 Redux store,用来存储应用程序中的所有状态。createStore 函数接受三个参数:reducer、preloadedState 和 enhancer。

  • reducer:用来处理应用程序的状态变化的函数;
  • preloadedState:应用程序的初始状态;
  • enhancer:用来增强 createStore 函数的能力的函数。

createStore 函数的源码实现

下面是 createStore 函数的源码实现:

export default function createStore(reducer, preloadedState, enhancer) {
  let currentReducer = reducer;
  let currentState = preloadedState;
  let currentListeners = [];
  let nextListeners = currentListeners;
  let isDispatching = false;

  function ensureCanMutateNextListeners() {
    if (nextListeners === currentListeners) {
      nextListeners = currentListeners.slice();
    }
  }

  function getState() {
    return currentState;
  }

  function subscribe(listener) {
    if (typeof listener !== 'function') {
      throw new Error('Expected the listener to be a function.');
    }

    let isSubscribed = true;

    ensureCanMutateNextListeners();
    nextListeners.push(listener);

    return function unsubscribe() {
      if (!isSubscribed) {
        return;
      }

      isSubscribed = false;

      ensureCanMutateNextListeners();
      const index = nextListeners.indexOf(listener);
      nextListeners.splice(index, 1);
      currentListeners = null;
    };
  }

  function dispatch(action) {
    if (!isPlainObject(action)) {
      throw new Error(
        'Actions must be plain objects. ' +
          'Use custom middleware for async actions.'
      );
    }

    if (typeof action.type === 'undefined') {
      throw new Error(
        'Actions may not have an undefined "type" property. ' +
          'Have you misspelled a constant?'
      );
    }

    if (isDispatching) {
      throw new Error('Reducers may not dispatch actions.');
    }

    try {
      isDispatching = true;
      currentState = currentReducer(currentState, action);
    } finally {
      isDispatching = false;
    }

    const listeners = (currentListeners = nextListeners);
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i];
      listener();
    }

    return action;
  }

  function replaceReducer(nextReducer) {
    if (typeof nextReducer !== 'function') {
      throw new Error('Expected the nextReducer to be a function.');
    }

    currentReducer = nextReducer;

    dispatch({ type: ActionTypes.REPLACE });
  }

  dispatch({ type: ActionTypes.INIT });

  return {
    dispatch,
    subscribe,
    getState,
    replaceReducer,
  };
}

createStore 函数的分析

下面我们来逐行分析一下 createStore 函数的源码实现。

第 1 行,我们使用 export default 关键字将 createStore 函数导出。

第 3 行到第 10 行,我们定义了一些变量,用来存储当前的 reducer、状态、监听器以及 dispatch 函数是否正在执行。

第 12 行到第 18 行,我们定义了一个名为 ensureCanMutateNextListeners 的函数,用来确保 nextListeners 可以被修改。

第 20 行到第 26 行,我们定义了一个名为 getState 的函数,用来获取当前的状态。

第 28 行到第 41 行,我们定义了一个名为 subscribe 的函数,用来订阅状态的变化。该函数接受一个回调函数作为参数,该回调函数会在状态发生变化时被触发。subscribe 函数返回一个用于取消订阅的函数。

第 43 行到第 71 行,我们定义了一个名为 dispatch 的函数,用来触发状态的变化。该函数接受一个 action 对象作为参数,该 action 对象用于描述状态的变化。dispatch 函数会将 action 对象传递给 reducer 函数,并根据 reducer 函数的返回值更新状态。在更新状态的过程中,dispatch 函数会依次执行所有订阅者的回调函数。

第 73 行到第 81 行,我们定义了一个名为 replaceReducer 的函数,用来替换当前的 reducer 函数。该函数接受一个新的 reducer 函数作为参数,该新的 reducer 函数会替换掉当前的 reducer 函数,并重新初始化 store。

最后,我们在第 83 行调用了 dispatch 函数,并返回一个对象,该对象包含了 dispatch、subscribe、getState 和 replaceReducer 四个方法。

createStore 函数的使用示例

下面是一个使用 createStore 函数的示例:

import { createStore } from 'redux';

function counter(state = 0, action) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    case 'DECREMENT':
      return state - 1;
    default:
      return state;
  }
}

const store = createStore(counter);

store.subscribe(() => {
  console.log(store.getState());
});

store.dispatch({ type: 'INCREMENT' });
store.dispatch({ type: 'INCREMENT' });
store.dispatch({ type: 'DECREMENT' });

在这个示例中,我们首先定义了一个名为 counter 的 reducer 函数,该函数用来处理应用程序的状态变化。然后,我们使用 createStore 函数创建了一个名为 store 的 Redux store,该 store 用来存储应用程序的状态。接着,我们使用 subscribe 函数订阅了 store 中状态的变化,并在状态发生变化时打印了当前的状态。最后,我们使用 dispatch 函数触发了三次状态的变化,并打印了变化后的状态。

总结

本文详细解析了 Redux 中最核心的函数之一:createStore 函数的源码实现。通过对 createStore 函数的分析,我们可以更深入地理解 Redux 的实现原理,从而更好地使用 Redux 来管理应用程序的状态。同时,本文还提供了一个使用 createStore 函数的示例,帮助我们更好地理解 createStore 函数的用法。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65be0e4fadd4f0e0ff7a25a6