Redux 是一个用于 JavaScript 应用的可预测状态容器,其核心原理基于 单向数据流 和 纯函数
一、Redux 核心原理
-
三大原则
- 单一数据源:整个应用状态存储在一个全局 Store 中。
- 状态只读 :只能通过
dispatch(action)
修改状态。 - 纯函数更新 :通过
reducer
纯函数计算新状态。
-
关键角色
- Store :保存状态,提供
dispatch
/subscribe
/getState
方法。 - Action :描述变化的普通对象(
{ type: 'ACTION_TYPE', payload }
)。 - Reducer :纯函数
(state, action) => newState
。
- Store :保存状态,提供
二、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();
四、关键设计解析
- 不可变状态
Reducer 必须返回新对象(如{ ...state, count: state.count + 1 }
),而不是直接修改原 state。 - 时间旅行调试
由于状态是纯函数计算的结果,可以轻松记录 action 和 state 的历史,实现时间旅行功能(如 Redux DevTools)。 - 中间件扩展
实际 Redux 通过applyMiddleware
增强dispatch
功能(如异步处理),这里未实现,但原理是通过包装dispatch
方法。