状态管理库(Redux/Vuex)中的设计模式
状态管理库如Redux和Vuex是现代前端开发中处理复杂应用状态的核心工具,它们通过特定的设计模式实现数据的集中管理和可预测性更新。这些库背后的设计思想与经典的设计模式紧密相关,理解这些模式能更高效地使用状态管理工具。
单例模式与全局状态管理
Redux和Vuex的核心设计都采用了单例模式,确保整个应用只有一个全局状态树。这种设计避免了状态分散导致的同步问题,同时提供了统一的状态访问入口。
// Redux中的store单例实现
import { createStore } from 'redux';
const initialState = { count: 0 };
function reducer(state = initialState, action) {
switch (action.type) {
case 'INCREMENT':
return { ...state, count: state.count + 1 };
default:
return state;
}
}
const store = createStore(reducer); // 全局唯一store实例
Vuex的实现类似:
// Vuex中的store单例
import { createStore } from 'vuex';
const store = createStore({
state() {
return { count: 0 };
},
mutations: {
increment(state) {
state.count++;
}
}
});
观察者模式与状态订阅
状态管理库使用观察者模式实现组件与状态的自动同步。当状态变化时,所有订阅该状态的组件都会收到通知并更新。
Redux的订阅机制:
// 订阅状态变化
const unsubscribe = store.subscribe(() => {
console.log('State changed:', store.getState());
});
// 触发状态变化
store.dispatch({ type: 'INCREMENT' });
// 取消订阅
unsubscribe();
Vuex通过Vue的响应式系统自动处理依赖追踪:
<template>
<div>{{ $store.state.count }}</div>
</template>
<script>
export default {
mounted() {
// 自动建立依赖关系
console.log(this.$store.state.count);
}
}
</script>
命令模式与Action/Commit
状态变更通过明确的命令(Action/Mutation)进行,这体现了命令模式的思想。将状态修改封装为离散的命令,使变更可追踪和可回放。
Redux中的action:
// Action创建函数
function increment() {
return { type: 'INCREMENT' };
}
// 触发action
store.dispatch(increment());
// 带参数的action
function addTodo(text) {
return { type: 'ADD_TODO', payload: { text } };
}
Vuex中的mutation:
const store = createStore({
mutations: {
addTodo(state, payload) {
state.todos.push(payload.text);
}
}
});
// 提交mutation
store.commit('addTodo', { text: 'Learn Vuex' });
装饰器模式与中间件
Redux中间件系统是装饰器模式的典型应用,可以在不修改核心逻辑的情况下增强dispatch功能。
// 自定义logger中间件
const logger = store => next => action => {
console.log('dispatching', action);
let result = next(action);
console.log('next state', store.getState());
return result;
};
// 应用中间件
const store = createStore(
reducer,
applyMiddleware(logger)
);
Vuex也有类似的插件机制:
const myPlugin = store => {
store.subscribe((mutation, state) => {
console.log(mutation.type, mutation.payload);
});
};
const store = createStore({
// ...
plugins: [myPlugin]
});
策略模式与Reducer设计
Redux的reducer函数体现了策略模式,通过不同的action类型选择不同的状态处理策略。
function todosReducer(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return [...state, action.payload];
case 'TOGGLE_TODO':
return state.map(todo =>
todo.id === action.payload.id
? { ...todo, completed: !todo.completed }
: todo
);
default:
return state;
}
}
组合模式与模块化
大型应用的状态管理需要模块化组织,这体现了组合模式的思想。
Redux的combineReducers:
import { combineReducers } from 'redux';
const rootReducer = combineReducers({
todos: todosReducer,
visibilityFilter: visibilityFilterReducer
});
Vuex的模块系统:
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const store = createStore({
modules: {
a: moduleA,
b: moduleB
}
})
备忘录模式与时间旅行调试
Redux DevTools实现的时间旅行功能基于备忘录模式,可以保存和恢复状态快照。
// 手动实现简单的时间旅行
const states = [];
let currentState = 0;
function saveState(state) {
states.push(JSON.parse(JSON.stringify(state)));
currentState = states.length - 1;
}
function undo() {
if (currentState > 0) {
currentState--;
return states[currentState];
}
return null;
}
function redo() {
if (currentState < states.length - 1) {
currentState++;
return states[currentState];
}
return null;
}
代理模式与Getter计算
Vuex的getters提供了派生状态的机制,这类似于代理模式,可以在访问状态时进行额外计算。
const store = createStore({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done);
},
doneTodosCount: (state, getters) => {
return getters.doneTodos.length;
}
}
});
// 访问getter
store.getters.doneTodos; // -> [{ id: 1, text: '...', done: true }]
工厂模式与Action创建
Redux中的action创建函数和Vuex中的action方法都体现了工厂模式,封装了action对象的创建过程。
// Redux action工厂函数
function makeActionCreator(type, ...argNames) {
return function(...args) {
const action = { type };
argNames.forEach((arg, index) => {
action[argNames[index]] = args[index];
});
return action;
};
}
const ADD_TODO = 'ADD_TODO';
const addTodo = makeActionCreator(ADD_TODO, 'text', 'id');
console.log(addTodo('Learn Redux', 1));
// { type: 'ADD_TODO', text: 'Learn Redux', id: 1 }
Vuex中的异步action:
actions: {
async fetchUser({ commit }, userId) {
try {
const user = await api.fetchUser(userId);
commit('SET_USER', user);
} catch (error) {
commit('SET_ERROR', error);
}
}
}
状态模式与状态机
复杂的状态逻辑可以通过状态模式来管理,这在Redux和Vuex中都有体现。
// 订单状态机
const orderStateMachine = {
pending: {
confirm: 'confirmed',
cancel: 'cancelled'
},
confirmed: {
ship: 'shipped',
cancel: 'cancelled'
},
shipped: {
deliver: 'delivered'
}
};
function orderReducer(state = { status: 'pending' }, action) {
const nextStatus = orderStateMachine[state.status]?.[action.type];
if (!nextStatus) return state;
return { ...state, status: nextStatus };
}
依赖注入与Provider模式
React-Redux的Provider组件实现了依赖注入模式,将store注入到组件树中。
import { Provider } from 'react-redux';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
// 组件中通过connect获取store
function connect(mapStateToProps) {
return function(WrappedComponent) {
return function(props) {
const state = useReduxState();
const stateProps = mapStateToProps(state);
return <WrappedComponent {...props} {...stateProps} />;
};
};
}
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
下一篇:组件通信中的设计模式选择