Redux 状态管理实现

手写简易 Redux 的 createStore、dispatch、subscribe

问题

从零实现一个简易版 Redux,包含 createStoregetStatedispatchsubscribe 功能。

解答

实现 createStore

function createStore(reducer, initialState) {
  let state = initialState;
  let listeners = [];

  // 获取当前状态
  function getState() {
    return state;
  }

  // 派发 action,更新状态
  function dispatch(action) {
    // 调用 reducer 计算新状态
    state = reducer(state, action);
    // 通知所有订阅者
    listeners.forEach(listener => listener());
    return action;
  }

  // 订阅状态变化
  function subscribe(listener) {
    listeners.push(listener);
    // 返回取消订阅函数
    return function unsubscribe() {
      const index = listeners.indexOf(listener);
      listeners.splice(index, 1);
    };
  }

  // 初始化状态
  dispatch({ type: '@@REDUX/INIT' });

  return {
    getState,
    dispatch,
    subscribe
  };
}

使用示例

// 定义 reducer
function counterReducer(state = { count: 0 }, action) {
  switch (action.type) {
    case 'INCREMENT':
      return { count: state.count + 1 };
    case 'DECREMENT':
      return { count: state.count - 1 };
    default:
      return state;
  }
}

// 创建 store
const store = createStore(counterReducer);

// 订阅状态变化
const unsubscribe = store.subscribe(() => {
  console.log('状态更新:', store.getState());
});

// 派发 action
store.dispatch({ type: 'INCREMENT' }); // 状态更新: { count: 1 }
store.dispatch({ type: 'INCREMENT' }); // 状态更新: { count: 2 }
store.dispatch({ type: 'DECREMENT' }); // 状态更新: { count: 1 }

// 取消订阅
unsubscribe();
store.dispatch({ type: 'INCREMENT' }); // 不再打印
console.log(store.getState()); // { count: 2 }

支持中间件的增强版

function createStore(reducer, initialState, enhancer) {
  // 如果有 enhancer,交给 enhancer 处理
  if (typeof enhancer === 'function') {
    return enhancer(createStore)(reducer, initialState);
  }

  let state = initialState;
  let listeners = [];

  function getState() {
    return state;
  }

  function dispatch(action) {
    state = reducer(state, action);
    listeners.forEach(listener => listener());
    return action;
  }

  function subscribe(listener) {
    listeners.push(listener);
    return () => {
      listeners = listeners.filter(l => l !== listener);
    };
  }

  dispatch({ type: '@@REDUX/INIT' });

  return { getState, dispatch, subscribe };
}

// 实现 applyMiddleware
function applyMiddleware(...middlewares) {
  return (createStore) => (reducer, initialState) => {
    const store = createStore(reducer, initialState);
    let dispatch = store.dispatch;

    const middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    };

    // 给每个中间件传入 middlewareAPI
    const chain = middlewares.map(middleware => middleware(middlewareAPI));
    // 组合中间件,增强 dispatch
    dispatch = compose(...chain)(store.dispatch);

    return { ...store, dispatch };
  };
}

// compose 函数
function compose(...funcs) {
  if (funcs.length === 0) return arg => arg;
  if (funcs.length === 1) return funcs[0];
  return funcs.reduce((a, b) => (...args) => a(b(...args)));
}

中间件使用示例

// logger 中间件
const logger = ({ getState }) => (next) => (action) => {
  console.log('dispatching:', action);
  const result = next(action);
  console.log('next state:', getState());
  return result;
};

// 创建带中间件的 store
const store = createStore(
  counterReducer,
  undefined,
  applyMiddleware(logger)
);

store.dispatch({ type: 'INCREMENT' });
// dispatching: { type: 'INCREMENT' }
// next state: { count: 1 }

关键点

  • getState 返回当前状态的引用
  • dispatch 调用 reducer 计算新状态,然后通知所有订阅者
  • subscribe 返回取消订阅函数,实现发布-订阅模式
  • 中间件本质是对 dispatch 的增强,形成洋葱模型
  • compose 将多个函数从右到左组合成一个函数