createReactivePinia
不依赖任何第三方框架的精简版 Pinia 状态管理系统。
函数签名
typescript
// 创建 Pinia 实例
function createReactivePinia(deps: PiniaDeps): PiniaInstance
// 定义 Store
function defineStore<S, G, A>(
options: DefineStoreOptions<S, G, A>,
pinia: PiniaInstance,
deps: PiniaDeps
): () => Store<S, G, A>
// 插件
function createPersistPlugin(deps: PersistPluginDeps): PiniaPlugin
function createLogPlugin(deps: LogPluginDeps): PiniaPlugin
interface PiniaDeps {
/** 创建响应式对象 */
createReactive: CreateReactive
/** 控制台日志函数 */
log: (...args: any[]) => void
/** 控制台警告函数 */
warn: (...args: any[]) => void
}
interface DefineStoreOptions<S, G, A> {
/** Store ID */
id: string
/** 状态定义 */
state?: () => S
/** 计算属性定义 */
getters?: G
/** 方法定义 */
actions?: A
}前置依赖
依赖参数
| 参数名 | 类型 | 说明 |
|---|---|---|
deps.createReactive | CreateReactive | 创建响应式对象的函数,用于实现状态的自动更新 |
deps.log | (...args: any[]) => void | 日志输出函数,用于记录操作日志 |
deps.warn | (...args: any[]) => void | 警告输出函数,用于记录警告信息 |
环境要求
- createReactive: 需要先导入
createReactive函数
bash
# 确保已安装相关依赖
npm install shared参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
options | DefineStoreOptions | 是 | Store 配置对象 |
options.id | string | 是 | Store 的唯一标识 |
options.state | () => StateTree | 否 | 状态定义函数 |
options.getters | Getters | 否 | 计算属性定义对象 |
options.actions | Actions | 否 | 方法定义对象 |
pinia | PiniaInstance | 是 | Pinia 实例 |
deps | PiniaDeps | 是 | 环境依赖 |
返回值
| 类型 | 说明 |
|---|---|
PiniaInstance | Pinia 实例,用于管理所有 Store |
() => Store | Store 工厂函数,调用后返回 Store 实例 |
工作原理
- 响应式状态管理:使用
createReactive创建响应式的状态对象 - Getters 缓存:计算属性自动缓存,状态变化时清除缓存
- Actions 绑定:方法自动绑定到 Store 实例
- 订阅机制:支持订阅状态变化,自动通知订阅者
- 插件系统:支持添加插件扩展功能
- 模块化管理:每个 Store 独立管理,支持多 Store 共存
核心特性:
- 完全不依赖 Vue 或其他框架
- 基于响应式系统,自动追踪状态变化
- 支持 State、Getters、Actions
- 支持 $patch、$reset、$subscribe 等工具方法
- 支持插件系统(持久化、日志等)
- TypeScript 完整类型支持
完整示例
typescript
import { createReactivePinia, defineStore } from 'zcw-shared/reactive/createReactivePinia'
import { createReactive } from 'zcw-shared/reactive/createReactive'
// 1. 创建 Pinia 实例
const pinia = createReactivePinia({
createReactive,
log: console.log,
warn: console.warn
})
// 2. 定义 Counter Store
const useCounterStore = defineStore({
id: 'counter',
state: () => ({
count: 0,
name: 'Counter'
}),
getters: {
doubleCount: (state) => state.count * 2,
greeting: (state) => `Hello, ${state.name}!`
},
actions: {
increment() {
this.$state.count++
},
decrement() {
this.$state.count--
},
incrementBy(amount: number) {
this.$state.count += amount
}
}
}, pinia, {
createReactive,
log: console.log,
warn: console.warn
})
// 3. 使用 Store
const counter = useCounterStore()
// 访问状态
console.log(counter.count) // 0
console.log(counter.name) // 'Counter'
// 访问 getters
console.log(counter.doubleCount) // 0
console.log(counter.greeting) // 'Hello, Counter!'
// 调用 actions
counter.increment()
console.log(counter.count) // 1
console.log(counter.doubleCount) // 2
counter.incrementBy(5)
console.log(counter.count) // 6
// 批量更新(对象方式)
counter.$patch({
count: 100,
name: 'New Counter'
})
// 批量更新(函数方式)
counter.$patch((state) => {
state.count = 200
state.name = 'Updated Counter'
})
// 订阅状态变化
const unsubscribe = counter.$subscribe((mutation, state) => {
console.log('状态已变化:', state)
})
// 重置状态
counter.$reset()
console.log(counter.count) // 0
// 取消订阅
unsubscribe()多 Store 示例
typescript
// User Store
const useUserStore = defineStore({
id: 'user',
state: () => ({
username: 'Guest',
email: '',
isLoggedIn: false
}),
getters: {
userInfo: (state) => `${state.username} (${state.email})`
},
actions: {
login(username: string, email: string) {
this.$state.username = username
this.$state.email = email
this.$state.isLoggedIn = true
},
logout() {
this.$state.username = 'Guest'
this.$state.email = ''
this.$state.isLoggedIn = false
}
}
}, pinia, deps)
// Todo Store
const useTodoStore = defineStore({
id: 'todo',
state: () => ({
todos: [] as Array<{ id: number; text: string; done: boolean }>,
nextId: 1
}),
getters: {
completedTodos: (state) => state.todos.filter(t => t.done),
activeTodos: (state) => state.todos.filter(t => !t.done),
todoCount: (state) => state.todos.length
},
actions: {
addTodo(text: string) {
this.$state.todos.push({
id: this.$state.nextId++,
text,
done: false
})
},
toggleTodo(id: number) {
const todo = this.$state.todos.find(t => t.id === id)
if (todo) {
todo.done = !todo.done
}
}
}
}, pinia, deps)
// 使用多个 Store
const user = useUserStore()
const todo = useTodoStore()
user.login('Alice', 'alice@example.com')
todo.addTodo('Learn Pinia')
todo.addTodo('Build App')
console.log(user.userInfo) // 'Alice (alice@example.com)'
console.log(todo.todoCount) // 2插件系统
日志插件
typescript
import { createLogPlugin } from 'zcw-shared/reactive/createReactivePinia'
const logPlugin = createLogPlugin({
log: console.log
})
pinia.use(logPlugin)
// 所有 Store 的状态变化都会被记录持久化插件
typescript
import { createPersistPlugin } from 'zcw-shared/reactive/createReactivePinia'
const persistPlugin = createPersistPlugin({
getItem: (key: string) => localStorage.getItem(key),
setItem: (key: string, value: string) => localStorage.setItem(key, value),
log: console.log
})
pinia.use(persistPlugin)
// Store 状态会自动持久化到 localStorage自定义插件
typescript
// 创建自定义插件
function createTimestampPlugin() {
return ({ store }) => {
// 为每个 Store 添加 lastUpdated 属性
store.lastUpdated = Date.now()
// 订阅状态变化
store.$subscribe(() => {
store.lastUpdated = Date.now()
console.log(`Store ${store.$id} 更新于 ${new Date(store.lastUpdated).toLocaleString()}`)
})
}
}
pinia.use(createTimestampPlugin())Store API
状态访问
typescript
const counter = useCounterStore()
// 直接访问
console.log(counter.count)
// 通过 $state 访问
console.log(counter.$state.count)
// 修改状态
counter.count = 10
counter.$state.count = 10$patch - 批量更新
typescript
// 对象方式
counter.$patch({
count: 100,
name: 'New Name'
})
// 函数方式(推荐,可以访问当前状态)
counter.$patch((state) => {
state.count += 10
state.name = state.name.toUpperCase()
})$reset - 重置状态
typescript
// 重置到初始状态
counter.$reset()$subscribe - 订阅变化
typescript
const unsubscribe = counter.$subscribe((mutation, state) => {
console.log('Mutation type:', mutation.type)
console.log('New state:', state)
})
// 取消订阅
unsubscribe()$dispose - 销毁 Store
typescript
// 销毁单个 Store
counter.$dispose()
// 销毁所有 Store
pinia.dispose()实际应用场景
Vue 组件中使用
typescript
import { defineComponent, computed } from 'vue'
import { useCounterStore } from './stores/counter'
export default defineComponent({
setup() {
const counter = useCounterStore()
// 直接使用 store
return {
count: computed(() => counter.count),
doubleCount: computed(() => counter.doubleCount),
increment: () => counter.increment(),
decrement: () => counter.decrement()
}
}
})React Hook 中使用
typescript
import { useState, useEffect } from 'react'
import { useCounterStore } from './stores/counter'
function useCounter() {
const counter = useCounterStore()
const [count, setCount] = useState(counter.count)
useEffect(() => {
const unsubscribe = counter.$subscribe((_, state) => {
setCount(state.count)
})
return unsubscribe
}, [])
return {
count,
increment: () => counter.increment(),
decrement: () => counter.decrement()
}
}Node.js 中使用
typescript
// 服务端状态管理
const useAppStateStore = defineStore({
id: 'appState',
state: () => ({
serverStartTime: Date.now(),
requestCount: 0,
activeConnections: 0
}),
getters: {
uptime: (state) => Date.now() - state.serverStartTime
},
actions: {
incrementRequestCount() {
this.$state.requestCount++
},
updateConnections(count: number) {
this.$state.activeConnections = count
}
}
}, pinia, deps)
const appState = useAppStateStore()
// 在请求处理中使用
app.use((req, res, next) => {
appState.incrementRequestCount()
next()
})高级用法
Store 组合
typescript
// 在一个 Store 中使用另一个 Store
const useCartStore = defineStore({
id: 'cart',
state: () => ({
items: [] as Array<{ id: number; quantity: number }>
}),
actions: {
addItem(id: number) {
// 访问其他 Store
const user = useUserStore()
if (!user.isLoggedIn) {
console.warn('请先登录')
return
}
this.$state.items.push({ id, quantity: 1 })
}
}
}, pinia, deps)状态同步
typescript
// 同步多个 Store 的状态
const counter1 = useCounterStore()
const counter2 = useCounterStore() // 返回同一个实例
console.log(counter1 === counter2) // true
counter1.increment()
console.log(counter2.count) // 1动态 Store
typescript
// 动态创建 Store
function createDynamicStore(id: string, initialCount: number) {
return defineStore({
id,
state: () => ({
count: initialCount
}),
actions: {
increment() {
this.$state.count++
}
}
}, pinia, deps)
}
const store1 = createDynamicStore('dynamic-1', 0)()
const store2 = createDynamicStore('dynamic-2', 100)()
console.log(store1.count) // 0
console.log(store2.count) // 100与 Pinia 的对比
| 特性 | 精简版 Pinia | 官方 Pinia |
|---|---|---|
| State | ✅ | ✅ |
| Getters | ✅ | ✅ |
| Actions | ✅ | ✅ |
| $patch | ✅ | ✅ |
| $reset | ✅ | ✅ |
| $subscribe | ✅ | ✅ |
| 插件系统 | ✅ | ✅ |
| Vue DevTools | ❌ | ✅ |
| HMR | ❌ | ✅ |
| Setup Stores | ❌ | ✅ |
| 依赖框架 | ❌ | Vue 3 |
性能优化
typescript
// 1. Getters 会自动缓存
const counter = useCounterStore()
console.log(counter.doubleCount) // 计算
console.log(counter.doubleCount) // 使用缓存
// 2. 使用 $patch 批量更新,减少通知次数
counter.$patch((state) => {
state.count += 1
state.name = 'New'
// 只触发一次订阅通知
})
// 3. 及时取消订阅
const unsubscribe = counter.$subscribe(() => {})
// ... 使用完毕后
unsubscribe()精简版 Pinia,让状态管理变得简单而高效,完全不依赖任何框架!