Skip to content

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.createReactiveCreateReactive创建响应式对象的函数,用于实现状态的自动更新
deps.log(...args: any[]) => void日志输出函数,用于记录操作日志
deps.warn(...args: any[]) => void警告输出函数,用于记录警告信息

环境要求

  • createReactive: 需要先导入 createReactive 函数
bash
# 确保已安装相关依赖
npm install shared

参数

参数名类型必填说明
optionsDefineStoreOptionsStore 配置对象
options.idstringStore 的唯一标识
options.state() => StateTree状态定义函数
options.gettersGetters计算属性定义对象
options.actionsActions方法定义对象
piniaPiniaInstancePinia 实例
depsPiniaDeps环境依赖

返回值

类型说明
PiniaInstancePinia 实例,用于管理所有 Store
() => StoreStore 工厂函数,调用后返回 Store 实例

工作原理

  1. 响应式状态管理:使用 createReactive 创建响应式的状态对象
  2. Getters 缓存:计算属性自动缓存,状态变化时清除缓存
  3. Actions 绑定:方法自动绑定到 Store 实例
  4. 订阅机制:支持订阅状态变化,自动通知订阅者
  5. 插件系统:支持添加插件扩展功能
  6. 模块化管理:每个 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,让状态管理变得简单而高效,完全不依赖任何框架!