Redux 状态管理实现
手写简易 Redux 的 createStore、dispatch、subscribe
问题
从零实现一个简易版 Redux,包含 createStore、getState、dispatch、subscribe 功能。
解答
实现 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将多个函数从右到左组合成一个函数
目录