主题
pinia与vuex对比与使用剖析
vuex与pinia的区别
pinia
的特点是采用ts编写的, 类型提示友好, 体积小, 使用简单pinia
去除了mutations
, 它只有state
,getters
,actions
(包括了同步和异步)pinia
同时支持conpositionApi
同时也兼容optionsApi
, 可以无痛将vue3
代码直接迁移到pinia
中- Vuex中需要使用module来定义模块(嵌套问题), 树结构(module套module), vuex中的命名空间的概念(namespaced)。 整个数据定义树结构 $store.state.a.b.c.xxx (createNamespaceHelpers()), 所有的模块的状态会自动定义到跟模块上, 所以会出现模块覆盖跟状态.
- vuex中只允许程序有有一个store
- pinia可以采用多个store, store之间可以互相调用(扁平化), 不用担心命名冲突问题
pinia需要vue版本是3.3
pinia的使用示例
1 . 安装
bash
pnpm add pinia
# or
npm install pinia
2. 使用
main.js
js
import {createPinia} from 'pinia';
import {createApp} from 'vue';
const pinia = createPinia()
const app = createApp()
app.use(pinia)
app.mount('#app')
src/store/counter.js
与App.vue
src/store/counter.js
js
import {defineStore} from 'pinia';
export const useCounterStore = defineStore('counter', {
state:{ // --> reactive({count:0})
count: 0
},
getters:{ // -->computed
double() {
return this.count * 2
}
},
actions:{ // --> methods
add(payload) {
this.count += payload
}
}
})
App.vue
vue
<script setup>
import { useCountStore } from './store/counter';
const store = useCountStore()
</script>
<template>
<div>
计数器:{{store.count}}
</div>双倍:{{store.double}}</div>
<button @click="store.add(2)">累加</button>
</template>
注意:
pinia中的state其实就是一个响应式对象, 因此可以直接在组件中直接修改state的值, 但是不建议
pinia中defineStore方法, 支持optionsApi和componsitionsApi,
- 若是componsitionsApi, 则第一个参数是storeId, 一个唯一的名字, 第二个参数是一个setup函数, 这个setup函数其实就是组件中的setup函数
jsimport { defineStore } from 'pinia'; import { ref, computed } from 'vue'; export const useCountStore = defineStore('counter', ()=>{ const state = ref(0) const double = computed(()=>{ return state.value * 2 }) const add = (payload)=>{ return state += payload } return { state, double, add } })
- 若是optionsAPI, 则可以个参数可以是storeId, 第二个参数是一个对象, 如
src/store/counter.js
- optionsAPI第一个参数也可以是一个对象, 但是里面得有一个
id
属性, 值为storeId(store名字, 全局唯一), 其余的属性就是state, getters, actions, 没有mutations
jsimport { defineStore } from 'pinia'; export const useCounterStore = defineStore({ id:'counter', state:{ count: 0 }, getters:{ double() { return this.count * 2 } }, actions:{ add(payload) { this.count += payload; } } })
剖析pinia
的实现
vue3中若想某个属性所有的组件都能使用
vue.config.globalPrototype.$xxx = xxx ,这样所有组件都能通过$xxx来访问, 因为vue3不再是类封装的
例如:
js
const pinia = {
install(app) {
// 我们期望所有组件都可以访问到这个pinia
app.config.globalProtptypes.$pinia = pinia
// Vue2是将$pinia挂载到Vue.prototype上
// Vue.prototype.$pinia = pinia
// Vue3可以通过inject注入使用
app.provide(PiniaSymbol, pinia)
}
}
createPinia内部会将项目中每一个store都注册进app内, 在defineStore方法中检测是否有注册过store, key是storeId, value 是对应的store, 若注册过则不再注册, 而是直接取用, 反之则先注册, 注册后写入store 存储的Map中, 再直接取用