# 状态管理(pinia)
Mpx 参考 Pinia (opens new window) 设计实现了一套外部状态逻辑管理系统(pinia),允许跨页面/组件共享状态,其中的概念与 api 与 Pinia 保持一致,同时支持在 Mpx 组合式 API(Composition API)和选项式 API(Options API)模式下使用。
# 介绍
pinia
是一个状态管理容器,可支持复杂场景下的组件通信机制,与Vuex
状态管理不同之处在于:
mutations 不再存在,使用 actions 来支持应用中状态的同步和异步变更。
动态创建 store,使用
useStore
实现运行时动态创建 store。扁平架构,不再有 modules 嵌套结构,支持不同 store 之间的交叉组合方式使用。
# 创建 pinia
首先在应用中调用createPinia
方法来创建全局 pinia 实例。
// app.mpx
import mpx from '@mpxjs/core'
import { createPinia } from '@mpxjs/pinia'
const pinia = createPinia()
如果你的应用想使用 SSR 渲染模式,请将 pinia 的创建放在 onAppInit
钩子中执行
// app.mpx
import mpx, { createApp } from '@mpxjs/core'
import { createPinia } from '@mpxjs/pinia'
createApp({
// ...
onAppInit () {
const pinia = createPinia()
return {
pinia
}
}
})
# 创建 store
然后调用defineStore
方法,传入 store 唯一标识(id),来创建一个 store,支持 Setup 和 Options 两种风格的 store。
# Setup store
与组合式 API 的 setup 函数类似,我们可以传入一个函数,该函数定义了一些响应式属性和方法,并返回一个带有我们想暴露出去的属性和方法的对象。
// setup.js
import { defineStore } from '@mpxjs/pinia'
import { ref, computed } from '@mpxjs/core'
export const useSetupStore = defineStore('setup', () => {
const count = ref(0)
const name = ref('pinia')
const myName = computed(() => {
return name.value
})
function increment() {
count.value++
}
return { count, name, myName, increment }
})
在 Setup Store 中:
ref()
就是state
属性computed()
就是getters
function()
就是actions
# Options store
// options.js
import { defineStore } from '@mpxjs/pinia'
import { ref } from '@mpxjs/core'
export const useOptionsStore = defineStore('options', {
state : () => {
return {
count: 0,
name: 'pinia'
}
},
getters: {
myName(state) {
return state.name
}
},
actions: {
increment () {
this.$patch((state) => {
state.count++
})
}
}
})
# 使用 store
在选项式 API 中使用,如果你不能使用组合式 API,但你可以使用 computed
, methods
, '...',那你可以使用 mapState()
, mapActions()
辅助函数
来将 state
, getter
, action
等映射到你的组件中。
无论是 optionsStore、还是 setupStore,我们都可以在选项式组件中使用,且使用方式并无差异,下方例子我们统一使用 useSetupStore 来作为示范例
import { createComponent } from '@mpxjs/core'
import { storeToRefs, mapState, mapActions } from '@mpxjs/pinia'
import { useOptionsStore } from 'xxx/options'
import { useSetupStore } from 'xxx/setup'
// 选项式API(Options API)风格下通过mapHelper函数使用
createComponent({
computed: {
// 可以访问组件中的 this.name
// 此处与直接从 useSetupStore 中读取的数据相同
...mapState(useSetupStore, ['name', 'count']),
// 也可以将state修改别名,例如将name 注册为 otherName
...mapState(useSetupStore, {
otherName: 'name',
// 也可以写一个函数来获取对 useSetupStore 的访问权
double: store => store.count * 2,
// 也可以通过访问 `this` 拿到数据
magicValue() {
return this.count + this.double
}
}),
// 在pinia中,getter 也是通过 mapState 来进行映射
...mapState(useSetupStore, ['myName'])
},
methods: {
...mapActions(useSetupStore, ['increment']),
// 也可以将其注册问题 this.setupIncrement 方法
...mapActions(useSetupStore, {
setupIncrement: 'increment'
})
}
})
注意: 在 pinia
中,getter 也是通过 mapState 来进行映射
在组合式API (Setup API) 风格下使用
import { useSetupStore } from 'xxx/setup'
import { storeToRefs, mapState, mapActions } from '@mpxjs/pinia'
createComponent({
setup (props, context) {
const setupStore = useSetupStore()
setupStore.count = 2
// 作为 store 的一个属性,我们可以直接访问任何 getter(与 state )
setupStore.myName // pinia
function onIncrementClick() {
// 调用 action 方法
setupStore.increment()
console.log('New Count:', setupStore.count)
}
return {
onIncrementClick,
...storeToRefs(setupStore)
}
}
})
注意:在组合式 API(Setup API)模式下,直接解构获取到的 store 数据会失去响应性,需要通过 storeToRefs 方法处理赋予数据响应性。另外
storeToRefs
方法只会返回 state 或 getter。
# 使用插件
Mpx pinia 支持使用插件扩展当前 store 实例的功能,用法如下:
// onStoreAction.js,订阅所有store实例的方法
export const onStoreAction: context => {
context.store.$onAction((
{
name,
store,
args,
after,
onError
}) => {
after(name => {
console.error('after', name, store, args)
})
onError(error => {
console.log('onError', error)
})
}, false)
}
// app.mpx
import mpx from '@mpxjs/core'
import { createPinia } from '@mpxjs/pinia'
import { onStoreAction } from 'xxx/onStoreAction'
const pinia = createPinia()
pinia.use(onStoreAction)
← 状态管理(store) 使用 mixin →