Store 组合模式
在复杂应用中组合和组织 Pinia store 的高级模式,演示模块化架构、依赖注入和跨 store 通信策略。
功能特性
- 🏗️ 模块化 store 架构
- 🔗 跨 store 通信模式
- 💉 Store 依赖注入
- 🎯 Store 工厂模式
- 🔄 事件驱动的 store 交互
- 📦 Store 模块和命名空间
- 🧩 可组合的 store 工具
- 🎨 高阶 store 模式
- 🔒 Store 访问控制和权限
- 🧪 测试组合 store
核心类型
typescript
// types/store-composition.ts
export interface StoreModule {
id: string
name: string
dependencies?: string[]
permissions?: string[]
metadata?: Record<string, any>
}
export interface StoreRegistry {
stores: Map<string, any>
dependencies: Map<string, string[]>
permissions: Map<string, string[]>
}
export interface StoreEvent {
type: string
source: string
target?: string
payload?: any
timestamp: Date
}
export interface StoreFactory<T = any> {
create(config: any): T
destroy(store: T): void
configure(store: T, config: any): void
}
export interface ComposedStore {
modules: Record<string, any>
events: StoreEvent[]
registry: StoreRegistry
}
export interface StorePermission {
action: string
resource: string
condition?: (context: any) => boolean
}
Store 注册系统
typescript
// stores/registry.ts
import { defineStore } from 'pinia'
import type { StoreRegistry, StoreModule, StoreEvent } from '@/types'
export const useStoreRegistry = defineStore('store-registry', () => {
const registry = ref<StoreRegistry>({
stores: new Map(),
dependencies: new Map(),
permissions: new Map()
})
const events = ref<StoreEvent[]>([])
const eventListeners = ref<Map<string, Function[]>>(new Map())
// Store 注册
function registerStore(module: StoreModule, store: any) {
registry.value.stores.set(module.id, store)
if (module.dependencies) {
registry.value.dependencies.set(module.id, module.dependencies)
}
if (module.permissions) {
registry.value.permissions.set(module.id, module.permissions)
}
emitEvent({
type: 'store:registered',
source: 'registry',
payload: { module, store },
timestamp: new Date()
})
}
function unregisterStore(storeId: string) {
const store = registry.value.stores.get(storeId)
if (store) {
registry.value.stores.delete(storeId)
registry.value.dependencies.delete(storeId)
registry.value.permissions.delete(storeId)
emitEvent({
type: 'store:unregistered',
source: 'registry',
payload: { storeId, store },
timestamp: new Date()
})
}
}
// 依赖解析
function resolveDependencies(storeId: string): any[] {
const dependencies = registry.value.dependencies.get(storeId) || []
const resolved: any[] = []
for (const depId of dependencies) {
const depStore = registry.value.stores.get(depId)
if (!depStore) {
throw new Error(`未找到 store '${storeId}' 的依赖 '${depId}'`)
}
resolved.push(depStore)
}
return resolved
}
function validateDependencies(storeId: string): boolean {
const dependencies = registry.value.dependencies.get(storeId) || []
for (const depId of dependencies) {
if (!registry.value.stores.has(depId)) {
return false
}
}
return true
}
// 事件系统
function emitEvent(event: StoreEvent) {
events.value.push(event)
// 限制事件历史
if (events.value.length > 1000) {
events.value = events.value.slice(-500)
}
// 通知监听器
const listeners = eventListeners.value.get(event.type) || []
listeners.forEach(listener => {
try {
listener(event)
} catch (error) {
console.error(`事件监听器 '${event.type}' 出错:`, error)
}
})
}
function addEventListener(eventType: string, listener: Function) {
const listeners = eventListeners.value.get(eventType) || []
listeners.push(listener)
eventListeners.value.set(eventType, listeners)
return () => removeEventListener(eventType, listener)
}
function removeEventListener(eventType: string, listener: Function) {
const listeners = eventListeners.value.get(eventType) || []
const index = listeners.indexOf(listener)
if (index > -1) {
listeners.splice(index, 1)
eventListeners.value.set(eventType, listeners)
}
}
// Store 访问
function getStore<T = any>(storeId: string): T | undefined {
return registry.value.stores.get(storeId)
}
function hasStore(storeId: string): boolean {
return registry.value.stores.has(storeId)
}
function getAllStores(): Map<string, any> {
return new Map(registry.value.stores)
}
// 权限系统
function checkPermission(storeId: string, permission: string): boolean {
const permissions = registry.value.permissions.get(storeId) || []
return permissions.includes(permission) || permissions.includes('*')
}
// 计算属性
const storeCount = computed(() => registry.value.stores.size)
const registeredStores = computed(() => Array.from(registry.value.stores.keys()))
const recentEvents = computed(() => events.value.slice(-10))
return {
// 状态
registry: readonly(registry),
events: readonly(events),
// 操作
registerStore,
unregisterStore,
resolveDependencies,
validateDependencies,
emitEvent,
addEventListener,
removeEventListener,
getStore,
hasStore,
getAllStores,
checkPermission,
// 计算属性
storeCount,
registeredStores,
recentEvents
}
})
Store 工厂模式
typescript
// stores/factories/base-factory.ts
import { defineStore } from 'pinia'
import type { StoreFactory } from '@/types'
export interface BaseStoreConfig {
id: string
name: string
initialState?: Record<string, any>
actions?: Record<string, Function>
getters?: Record<string, Function>
plugins?: any[]
}
export class BaseStoreFactory implements StoreFactory {
private stores = new Map<string, any>()
create(config: BaseStoreConfig) {
if (this.stores.has(config.id)) {
return this.stores.get(config.id)
}
const store = defineStore(config.id, () => {
// 初始化状态
const state = reactive(config.initialState || {})
// 创建 getter
const getters: Record<string, ComputedRef> = {}
if (config.getters) {
Object.entries(config.getters).forEach(([key, getter]) => {
getters[key] = computed(() => getter(state))
})
}
// 创建操作
const actions: Record<string, Function> = {}
if (config.actions) {
Object.entries(config.actions).forEach(([key, action]) => {
actions[key] = (...args: any[]) => action(state, ...args)
})
}
// 添加通用操作
actions.$reset = () => {
Object.assign(state, config.initialState || {})
}
actions.$patch = (updates: any) => {
Object.assign(state, updates)
}
return {
...state,
...getters,
...actions
}
})
this.stores.set(config.id, store)
return store
}
destroy(store: any) {
const storeId = store.$id
if (this.stores.has(storeId)) {
this.stores.delete(storeId)
// 如需要,进行额外清理
}
}
configure(store: any, config: Partial<BaseStoreConfig>) {
// 动态重新配置逻辑
if (config.actions) {
Object.entries(config.actions).forEach(([key, action]) => {
store[key] = action
})
}
}
getStore(id: string) {
return this.stores.get(id)
}
getAllStores() {
return Array.from(this.stores.values())
}
}
// 实体 Store 工厂
export class EntityStoreFactory extends BaseStoreFactory {
create(config: BaseStoreConfig & {
entityName: string
apiEndpoint: string
schema?: any
}) {
const entityConfig = {
...config,
initialState: {
items: [],
loading: false,
error: null,
selectedId: null,
filters: {},
pagination: {
page: 1,
limit: 20,
total: 0
},
...config.initialState
},
actions: {
async fetchItems(state: any, params = {}) {
state.loading = true
state.error = null
try {
const response = await fetch(`${config.apiEndpoint}?${new URLSearchParams(params)}`)
const data = await response.json()
state.items = data.items || data
state.pagination = data.pagination || state.pagination
} catch (error) {
state.error = error.message
} finally {
state.loading = false
}
},
async createItem(state: any, item: any) {
try {
const response = await fetch(config.apiEndpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(item)
})
const newItem = await response.json()
state.items.push(newItem)
return newItem
} catch (error) {
state.error = error.message
throw error
}
},
async updateItem(state: any, id: string, updates: any) {
try {
const response = await fetch(`${config.apiEndpoint}/${id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(updates)
})
const updatedItem = await response.json()
const index = state.items.findIndex((item: any) => item.id === id)
if (index > -1) {
state.items[index] = updatedItem
}
return updatedItem
} catch (error) {
state.error = error.message
throw error
}
},
async deleteItem(state: any, id: string) {
try {
await fetch(`${config.apiEndpoint}/${id}`, {
method: 'DELETE'
})
state.items = state.items.filter((item: any) => item.id !== id)
} catch (error) {
state.error = error.message
throw error
}
},
selectItem(state: any, id: string | null) {
state.selectedId = id
},
setFilters(state: any, filters: any) {
state.filters = { ...state.filters, ...filters }
},
clearFilters(state: any) {
state.filters = {}
},
...config.actions
},
getters: {
selectedItem: (state: any) =>
state.items.find((item: any) => item.id === state.selectedId),
filteredItems: (state: any) => {
let filtered = state.items
Object.entries(state.filters).forEach(([key, value]) => {
if (value !== null && value !== undefined && value !== '') {
filtered = filtered.filter((item: any) => {
if (typeof value === 'string') {
return item[key]?.toString().toLowerCase().includes(value.toLowerCase())
}
return item[key] === value
})
}
})
return filtered
},
itemCount: (state: any) => state.items.length,
isLoading: (state: any) => state.loading,
hasError: (state: any) => !!state.error,
...config.getters
}
}
return super.create(entityConfig)
}
}
跨 Store 通信
typescript
// stores/communication/message-bus.ts
import { defineStore } from 'pinia'
import type { StoreEvent } from '@/types'
export interface Message {
id: string
type: string
from: string
to?: string
payload: any
timestamp: Date
handled: boolean
}
export const useMessageBus = defineStore('message-bus', () => {
const messages = ref<Message[]>([])
const handlers = ref<Map<string, Function[]>>(new Map())
const middleware = ref<Function[]>([])
// 发送消息
function send(type: string, payload: any, options: {
from: string
to?: string
priority?: 'low' | 'normal' | 'high'
}) {
const message: Message = {
id: `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
type,
from: options.from,
to: options.to,
payload,
timestamp: new Date(),
handled: false
}
// 应用中间件
let processedMessage = message
for (const mw of middleware.value) {
processedMessage = mw(processedMessage) || processedMessage
}
messages.value.push(processedMessage)
// 处理消息
handleMessage(processedMessage)
return message.id
}
// 处理消息
function handleMessage(message: Message) {
const typeHandlers = handlers.value.get(message.type) || []
const globalHandlers = handlers.value.get('*') || []
const allHandlers = [...typeHandlers, ...globalHandlers]
if (allHandlers.length === 0) {
console.warn(`未找到消息类型的处理器: ${message.type}`)
return
}
allHandlers.forEach(handler => {
try {
handler(message)
message.handled = true
} catch (error) {
console.error(`处理消息 ${message.id} 时出错:`, error)
}
})
}
// 订阅消息
function subscribe(type: string, handler: Function) {
const typeHandlers = handlers.value.get(type) || []
typeHandlers.push(handler)
handlers.value.set(type, typeHandlers)
return () => unsubscribe(type, handler)
}
// 取消订阅消息
function unsubscribe(type: string, handler: Function) {
const typeHandlers = handlers.value.get(type) || []
const index = typeHandlers.indexOf(handler)
if (index > -1) {
typeHandlers.splice(index, 1)
handlers.value.set(type, typeHandlers)
}
}
// 添加中间件
function addMiddleware(mw: Function) {
middleware.value.push(mw)
return () => {
const index = middleware.value.indexOf(mw)
if (index > -1) {
middleware.value.splice(index, 1)
}
}
}
// 请求-响应模式
function request(type: string, payload: any, options: {
from: string
timeout?: number
}): Promise<any> {
return new Promise((resolve, reject) => {
const requestId = `req-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
const timeout = options.timeout || 5000
// 设置响应处理器
const unsubscribe = subscribe(`${type}:response`, (message: Message) => {
if (message.payload.requestId === requestId) {
unsubscribe()
clearTimeout(timer)
if (message.payload.error) {
reject(new Error(message.payload.error))
} else {
resolve(message.payload.data)
}
}
})
// 设置超时
const timer = setTimeout(() => {
unsubscribe()
reject(new Error(`请求在 ${timeout}ms 后超时`))
}, timeout)
// 发送请求
send(type, { ...payload, requestId }, options)
})
}
// 响应请求
function respond(requestMessage: Message, data: any, error?: string) {
send(`${requestMessage.type}:response`, {
requestId: requestMessage.payload.requestId,
data,
error
}, {
from: 'message-bus',
to: requestMessage.from
})
}
// 清理旧消息
function cleanup(maxAge = 60000) {
const cutoff = new Date(Date.now() - maxAge)
messages.value = messages.value.filter(msg => msg.timestamp > cutoff)
}
// 计算属性
const messageCount = computed(() => messages.value.length)
const unhandledMessages = computed(() =>
messages.value.filter(msg => !msg.handled)
)
const recentMessages = computed(() =>
messages.value.slice(-20).reverse()
)
return {
// 状态
messages: readonly(messages),
// 操作
send,
subscribe,
unsubscribe,
addMiddleware,
request,
respond,
cleanup,
// 计算属性
messageCount,
unhandledMessages,
recentMessages
}
})
组合 Store 示例
typescript
// stores/composed/e-commerce.ts
import { defineStore } from 'pinia'
import { useStoreRegistry } from '@stores/registry'
import { useMessageBus } from '@stores/communication/message-bus'
import { EntityStoreFactory } from '@stores/factories/base-factory'
// 产品 Store
export const useProductsStore = defineStore('products', () => {
const registry = useStoreRegistry()
const messageBus = useMessageBus()
const factory = new EntityStoreFactory()
const baseStore = factory.create({
id: 'products',
name: '产品 Store',
entityName: 'product',
apiEndpoint: '/api/products',
initialState: {
categories: [],
brands: [],
priceRange: { min: 0, max: 1000 }
}
})
const store = baseStore()
// 在注册表中注册
registry.registerStore({
id: 'products',
name: '产品 Store',
permissions: ['read', 'write']
}, store)
// 订阅购物车事件
messageBus.subscribe('cart:item-added', (message) => {
const { productId, quantity } = message.payload
updateProductStock(productId, -quantity)
})
messageBus.subscribe('cart:item-removed', (message) => {
const { productId, quantity } = message.payload
updateProductStock(productId, quantity)
})
// 额外操作
async function updateProductStock(productId: string, change: number) {
const product = store.items.find(p => p.id === productId)
if (product) {
product.stock += change
// 通知其他 store
messageBus.send('product:stock-updated', {
productId,
newStock: product.stock,
change
}, { from: 'products' })
}
}
async function fetchCategories() {
try {
const response = await fetch('/api/categories')
store.categories = await response.json()
} catch (error) {
console.error('获取分类失败:', error)
}
}
return {
...store,
updateProductStock,
fetchCategories
}
})
// 购物车 Store
export const useCartStore = defineStore('cart', () => {
const registry = useStoreRegistry()
const messageBus = useMessageBus()
const items = ref<Array<{
id: string
productId: string
quantity: number
price: number
addedAt: Date
}>>([])
const isLoading = ref(false)
const error = ref<string | null>(null)
// 在注册表中注册
registry.registerStore({
id: 'cart',
name: '购物车 Store',
dependencies: ['products'],
permissions: ['read', 'write']
}, { items, isLoading, error })
// 订阅产品事件
messageBus.subscribe('product:stock-updated', (message) => {
const { productId, newStock } = message.payload
// 如果缺货则移除商品
if (newStock <= 0) {
removeItem(productId)
}
})
// 操作
async function addItem(productId: string, quantity = 1) {
try {
// 检查产品是否存在且有库存
const response = await messageBus.request('products:get-product', {
productId
}, { from: 'cart' })
const product = response.data
if (!product || product.stock < quantity) {
throw new Error('库存不足')
}
const existingItem = items.value.find(item => item.productId === productId)
if (existingItem) {
existingItem.quantity += quantity
} else {
items.value.push({
id: `cart-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
productId,
quantity,
price: product.price,
addedAt: new Date()
})
}
// 通知其他 store
messageBus.send('cart:item-added', {
productId,
quantity
}, { from: 'cart' })
} catch (error) {
console.error('添加商品到购物车失败:', error)
throw error
}
}
function removeItem(productId: string) {
const itemIndex = items.value.findIndex(item => item.productId === productId)
if (itemIndex > -1) {
const item = items.value[itemIndex]
items.value.splice(itemIndex, 1)
// 通知其他 store
messageBus.send('cart:item-removed', {
productId,
quantity: item.quantity
}, { from: 'cart' })
}
}
function updateQuantity(productId: string, newQuantity: number) {
const item = items.value.find(item => item.productId === productId)
if (item) {
const oldQuantity = item.quantity
item.quantity = newQuantity
const change = newQuantity - oldQuantity
messageBus.send('cart:quantity-updated', {
productId,
oldQuantity,
newQuantity,
change
}, { from: 'cart' })
}
}
function clearCart() {
const removedItems = [...items.value]
items.value = []
// 通知所有移除的商品
removedItems.forEach(item => {
messageBus.send('cart:item-removed', {
productId: item.productId,
quantity: item.quantity
}, { from: 'cart' })
})
}
// 计算属性
const itemCount = computed(() =>
items.value.reduce((total, item) => total + item.quantity, 0)
)
const totalPrice = computed(() =>
items.value.reduce((total, item) => total + (item.price * item.quantity), 0)
)
const isEmpty = computed(() => items.value.length === 0)
return {
// 状态
items: readonly(items),
isLoading: readonly(isLoading),
error: readonly(error),
// 操作
addItem,
removeItem,
updateQuantity,
clearCart,
// 计算属性
itemCount,
totalPrice,
isEmpty
}
})
// 订单 Store
export const useOrderStore = defineStore('order', () => {
const registry = useStoreRegistry()
const messageBus = useMessageBus()
const cartStore = useCartStore()
const orders = ref<any[]>([])
const currentOrder = ref<any | null>(null)
const isProcessing = ref(false)
// 在注册表中注册
registry.registerStore({
id: 'order',
name: '订单 Store',
dependencies: ['cart', 'products'],
permissions: ['read', 'write']
}, { orders, currentOrder, isProcessing })
// 操作
async function createOrder(orderData: any) {
if (cartStore.isEmpty) {
throw new Error('无法创建空购物车的订单')
}
isProcessing.value = true
try {
const order = {
id: `order-${Date.now()}`,
items: [...cartStore.items],
total: cartStore.totalPrice,
status: 'pending',
createdAt: new Date(),
...orderData
}
// 模拟 API 调用
await new Promise(resolve => setTimeout(resolve, 1000))
orders.value.push(order)
currentOrder.value = order
// 成功创建订单后清空购物车
cartStore.clearCart()
// 通知其他 store
messageBus.send('order:created', {
order
}, { from: 'order' })
return order
} finally {
isProcessing.value = false
}
}
async function updateOrderStatus(orderId: string, status: string) {
const order = orders.value.find(o => o.id === orderId)
if (order) {
order.status = status
order.updatedAt = new Date()
messageBus.send('order:status-updated', {
orderId,
status,
order
}, { from: 'order' })
}
}
// 计算属性
const orderCount = computed(() => orders.value.length)
const pendingOrders = computed(() =>
orders.value.filter(order => order.status === 'pending')
)
return {
// 状态
orders: readonly(orders),
currentOrder: readonly(currentOrder),
isProcessing: readonly(isProcessing),
// 操作
createOrder,
updateOrderStatus,
// 计算属性
orderCount,
pendingOrders
}
})
Store 组合工具
typescript
// composables/use-store-composition.ts
import { useStoreRegistry } from '@stores/registry'
import { useMessageBus } from '@stores/communication/message-bus'
export function useStoreComposition() {
const registry = useStoreRegistry()
const messageBus = useMessageBus()
// 组合多个 store
function composeStores<T extends Record<string, any>>(storeMap: T): T {
const composed = {} as T
Object.entries(storeMap).forEach(([key, storeFactory]) => {
const store = typeof storeFactory === 'function' ? storeFactory() : storeFactory
composed[key as keyof T] = store
})
return composed
}
// 创建带依赖的 store
function createStoreWithDeps<T>(
storeFactory: () => T,
dependencies: string[]
): T {
// 验证依赖
for (const dep of dependencies) {
if (!registry.hasStore(dep)) {
throw new Error(`未找到依赖 '${dep}'`)
}
}
return storeFactory()
}
// 创建带访问控制的 store 代理
function createSecureStore<T extends Record<string, any>>(
store: T,
permissions: string[]
): T {
return new Proxy(store, {
get(target, prop) {
const propName = prop.toString()
// 检查操作是否需要权限
if (typeof target[prop] === 'function' && propName.startsWith('$')) {
if (!permissions.includes('admin') && !permissions.includes(propName)) {
throw new Error(`操作权限被拒绝: ${propName}`)
}
}
return target[prop]
},
set(target, prop, value) {
const propName = prop.toString()
// 检查写权限
if (!permissions.includes('write') && !permissions.includes('admin')) {
throw new Error(`属性写权限被拒绝: ${propName}`)
}
target[prop] = value
return true
}
})
}
// Store 中间件
function applyMiddleware<T>(
store: T,
middleware: Array<(store: T, action: string, args: any[]) => any>
): T {
return new Proxy(store as any, {
get(target, prop) {
const value = target[prop]
if (typeof value === 'function') {
return (...args: any[]) => {
// 在操作前应用中间件
middleware.forEach(mw => {
mw(store, prop.toString(), args)
})
const result = value.apply(target, args)
// 处理异步结果
if (result instanceof Promise) {
return result.catch(error => {
// 应用错误中间件
middleware.forEach(mw => {
if (mw.name === 'errorMiddleware') {
mw(store, prop.toString(), [error])
}
})
throw error
})
}
return result
}
}
return value
}
})
}
return {
composeStores,
createStoreWithDeps,
createSecureStore,
applyMiddleware
}
}
// Store 组合钩子
export function useComposedStore<T extends Record<string, any>>(
composition: () => T
): T {
const stores = composition()
// 设置跨 store 响应性
Object.values(stores).forEach(store => {
if (store && typeof store === 'object' && '$subscribe' in store) {
store.$subscribe((mutation: any, state: any) => {
// 处理跨 store 状态同步
console.log(`Store ${store.$id} 发生变化:`, mutation)
})
}
})
return stores
}
测试组合 Store
typescript
// stores/__tests__/composition.test.ts
import { describe, it, expect, beforeEach, vi } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'
import { useProductsStore, useCartStore, useOrderStore } from '@stores/composed/e-commerce'
import { useStoreRegistry } from '@stores/registry'
import { useMessageBus } from '@stores/communication/message-bus'
describe('Store 组合', () => {
beforeEach(() => {
setActivePinia(createPinia())
})
it('应该注册带依赖的 store', () => {
const registry = useStoreRegistry()
const productsStore = useProductsStore()
const cartStore = useCartStore()
expect(registry.hasStore('products')).toBe(true)
expect(registry.hasStore('cart')).toBe(true)
expect(registry.validateDependencies('cart')).toBe(true)
})
it('应该处理跨 store 通信', async () => {
const messageBus = useMessageBus()
const productsStore = useProductsStore()
const cartStore = useCartStore()
// 模拟产品数据
productsStore.items.push({
id: 'product-1',
name: '测试产品',
price: 10,
stock: 5
})
// 添加商品到购物车
await cartStore.addItem('product-1', 2)
// 检查产品库存是否更新
const product = productsStore.items.find(p => p.id === 'product-1')
expect(product?.stock).toBe(3)
})
it('应该从购物车创建订单', async () => {
const productsStore = useProductsStore()
const cartStore = useCartStore()
const orderStore = useOrderStore()
// 设置测试数据
productsStore.items.push({
id: 'product-1',
name: '测试产品',
price: 10,
stock: 5
})
await cartStore.addItem('product-1', 2)
const order = await orderStore.createOrder({
customerName: '测试客户',
address: '测试地址'
})
expect(order).toBeDefined()
expect(order.items).toHaveLength(1)
expect(order.total).toBe(20)
expect(cartStore.isEmpty).toBe(true)
})
it('应该处理 store 事件', async () => {
const messageBus = useMessageBus()
const events: any[] = []
messageBus.subscribe('*', (event) => {
events.push(event)
})
const cartStore = useCartStore()
const productsStore = useProductsStore()
productsStore.items.push({
id: 'product-1',
name: '测试产品',
price: 10,
stock: 5
})
await cartStore.addItem('product-1', 1)
expect(events).toHaveLength(1)
expect(events[0].type).toBe('cart:item-added')
})
})
最佳实践
- 依赖管理: 始终明确声明 store 依赖关系
- 事件驱动通信: 使用消息总线实现松耦合
- 权限系统: 为敏感操作实现访问控制
- 工厂模式: 使用工厂创建相似的 store
- 测试: 测试 store 组合和跨 store 交互
- 性能: 监控消息总线性能并清理旧消息
- 文档: 记录 store 关系和通信模式
这个组合系统为构建复杂、可扩展的应用提供了坚实的基础,具有良好组织和可维护的 store 架构。