ByAI: Redux的typescript简化实现

Redux 是一个用于 JavaScript 应用的可预测状态容器,其核心原理基于 ​单向数据流 ​ 和 ​纯函数


一、Redux 核心原理

  1. ​三大原则​

    • 单一数据源:整个应用状态存储在一个全局 Store 中。
    • 状态只读 :只能通过 dispatch(action) 修改状态。
    • 纯函数更新 :通过 reducer 纯函数计算新状态。
  2. ​关键角色​

    • Store :保存状态,提供 dispatch/subscribe/getState 方法。
    • Action :描述变化的普通对象({ type: 'ACTION_TYPE', payload })。
    • Reducer :纯函数 (state, action) => newState。

二、TypeScript 实现

1. 定义类型

typescript 复制代码
// Action 类型:基础 Action 必须包含 type 字段
type Action = {
  type: string;
  [key: string]: any; // 允许其他任意字段(如 payload)
};

// Reducer 类型:接收当前 state 和 action,返回新 state
type Reducer<S = any, A extends Action = Action> = (state: S, action: A) => S;

// Store 类型:包含核心方法
interface Store<S = any, A extends Action = Action> {
  getState(): S;
  dispatch(action: A): void;
  subscribe(listener: () => void): () => void; // 返回取消订阅函数
}

2. 创建 Store

typescript 复制代码
function createStore<S, A extends Action>(
  reducer: Reducer<S, A>,
  initialState: S
): Store<S, A> {
  let state = initialState;
  const listeners: Array<() => void> = [];

  // 获取当前状态
  const getState = (): S => state;

  // 分发 Action
  const dispatch = (action: A): void => {
    state = reducer(state, action); // 调用 reducer 计算新状态
    listeners.forEach(listener => listener()); // 通知所有订阅者
  };

  // 订阅状态变化
  const subscribe = (listener: () => void): () => void => {
    listeners.push(listener);
    // 返回取消订阅函数
    return () => {
      const index = listeners.indexOf(listener);
      if (index !== -1) listeners.splice(index, 1);
    };
  };

  // 初始化时触发一次 dispatch(可选,用于兼容某些中间件)
  dispatch({ type: '@@INIT' } as A);

  return { getState, dispatch, subscribe };
}

3. 组合多个 Reducer(combineReducers)

typescript 复制代码
function combineReducers<Reducers extends Record<string, Reducer>>(
  reducers: Reducers
): Reducer {
  return (state: any = {}, action: Action): any => {
    const newState: any = {};
    Object.keys(reducers).forEach(key => {
      newState[key] = reducers[key](state[key], action); // 分别调用子 reducer
    });
    return newState;
  };
}

三、完整使用示例

typescript 复制代码
// 1. 定义 State 和 Action 类型
interface CounterState {
  count: number;
}

type CounterAction = 
  | { type: 'INCREMENT' }
  | { type: 'DECREMENT' }
  | { type: 'SET_COUNT'; payload: number };

// 2. 实现 Reducer
const counterReducer: Reducer<CounterState, CounterAction> = (
  state = { count: 0 },
  action
) => {
  switch (action.type) {
    case 'INCREMENT':
      return { count: state.count + 1 };
    case 'DECREMENT':
      return { count: state.count - 1 };
    case 'SET_COUNT':
      return { count: action.payload };
    default:
      return state;
  }
};

// 3. 创建 Store
const store = createStore(counterReducer, { count: 0 });

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

// 5. 分发 Action
store.dispatch({ type: 'INCREMENT' }); // State: { count: 1 }
store.dispatch({ type: 'SET_COUNT', payload: 10 }); // State: { count: 10 }

// 6. 取消订阅
unsubscribe();

四、关键设计解析

  1. 不可变状态
    Reducer 必须返回新对象(如 { ...state, count: state.count + 1 }),而不是直接修改原 state。
  2. 时间旅行调试
    由于状态是纯函数计算的结果,可以轻松记录 action 和 state 的历史,实现时间旅行功能(如 Redux DevTools)。
  3. 中间件扩展
    实际 Redux 通过 applyMiddleware 增强 dispatch 功能(如异步处理),这里未实现,但原理是通过包装 dispatch 方法。
相关推荐
HSunR29 分钟前
ruoyi 若依 自定义注解 参数校验
java·前端·数据库
拆房老料1 小时前
ONLYOFFICE也能像Microsoft Word和WPS一样分别设置中西文字体
前端·html·word·开源软件·wps
Solis程序员2 小时前
Stripe 幂等表:把「不确定的重试」变成「查表返回」
前端·安全·bootstrap·php·agent
李纲明2 小时前
WordPress 站点变慢:按 TTFB → 缓存 → 查询 → 前端 分层排查(含配置注意)
前端·缓存·性能优化·wordpress·后端开发
程序人生8882 小时前
PDF 转 Word 版式错乱、表格丢失?DocConverter Web 格式互转引擎的保真实践
前端·人工智能·opencv·机器学习·pdf·word
粥里有勺糖3 小时前
安利一下最近用的桌面“Agent” | T3 Code
前端·github·ai编程
xy34533 小时前
Axure 9.0 动态面板基本操作
前端·ui·html·axure·原型·产品设计
不停喝水3 小时前
【前端转全栈java速通课】 项目实战④7-11节 操作数据库-登录-注册-修改密码-注销-mubatis-plus简化crud-
java·前端·数据库
一水鉴天4 小时前
统一对象拓扑(UOT)设计全链定稿:从三件事分离到三继承 之1 20261010(豆包“查看聊天内容”继续)
前端·css
栖凤4 小时前
Java 的 try-catch 在 Agent 里失效了,我用了 5 个模式才兜住
java·前端·python