介绍
跟 Vuex 一样是数据状态管理系统,但是这个更轻量,整个包的大小是 1kb 。
- Vue2 和 Vue3 都支持
- 相比 Vuex 有更好更完美的
**TypeScript**
支持 - 模块化设计,你引入的每一个 store 在打包时都可以自动拆分他们
- 没有模块嵌套,只有 store 的概念, store 之间可以自由使用,更好的代码分割。
Pinia vs Vuex
版本问题:
- Vuex 当前最新版本是 4.x
- Vuex 4 用于 Vue3
- Vuex 3 用于 Vue2
- Pinia 当前最新版本是 2.x
- 既支持 Vue2 也支持 Vue3
Pinia api 与 Vuex ≤ 4 有很大不同,即:
- 没有
**mutations**
。 - 不再有模块的嵌套结构。
- 更好的
typescript
支持。无需创建自定义的复杂包装器来支持 TypeScript ,所有内容都是类型化的,并且 API 的设计方式尽可能地利用 TS 类型推断。 - 不再需要注入、导入函数、调用它们,享受自动补全。
- 无需动态添加 stores,默认情况下它们都是动态的。
- 没有命名空间模块。
基本使用
安装
yarn add pinia
// or
npm install pinia
如果你使用的是 vue2,你还需要安装组合式api : @vue/composition-api
注入
import { createApp } from 'vue'
import { createPinia } from 'pinia'
const pinia = createPinia()
createApp(App).use(pinia)
store
定义 store:
import { defineStore } from 'pinia'
/**
* defineStore 第一个参数:storeId,必须唯一;
* 第二个参数:配置对象
* state、getters、actions属性
*/
export const useStore = defineStore('main', {
// other option
})
使用 store:
import { storeToRefs } from 'pinia'
import { useStore } from '@/stores/counter'
export default {
setup() {
const store = useStore()
const { name, doubleCount } = storeToRefs(store)
cosnt { increment } = store
return {
name,
doubleCount,
increment
}
}
}
state
类似于组件的 data,用来存储全局状态。
- 必须是函数:为了在服务器渲染的时候避免交叉请求导致的数据状态污染
- 必须是箭头函数:为了更好的 TS 类型推导
import { defineStore } from 'pinia'
const useStore = defineStore('storeId', {
state: () => {
return {
counter: 0,
foo: 'hh',
arr: [1, 2, 3]
}
}
})
修改 state 的 4 种方式
我们可以 直接对 state 中的值进行更改
const store = useStore()
stote.counter++
也可以使用 $patch
来更改 state 中的多个属性值
store.$patch({
counter: store.counter + 1,
name: 'hello'
})
还可以给 $patch
传递函数,这种方式更适用于操作一些数组,对象等复杂一点的属性。
store.$patch((state) => {
state.arr.push(4)
state.counter++
})
通过 actions
的方式
store.changeState()
getters
类似于组件的 computed ,用来封装计算属性,有缓存功能,同一个 getters 就算被调用多次,只要值不变,依旧只执行一次。函数接收一个可选参数:state
。
import { defineStore } from 'pinia'
const useStore = defineStore('storeId', {
state: () => {
return {
counter: 0,
foo: 'hh',
arr: [1, 2, 3]
}
},
getters: {
doubleCount: (state) => state.counter * 2,
doubleCountPlusOne() {
return this.doubleCount + 1
},
count10 (state) {
return state.counter + 10
}
}
})
const store = useStore()
store.doubleCount
actions
类似于组件的 methods ,封装业务逻辑,修改 state。同步异步都支持
tips:不能使用箭头函数定义 action ,因为箭头函数绑定外部 this
import { defineStore } from 'pinia'
const useStore = defineStore('storeId', {
state: () => {
return {
counter: 0,
foo: 'hh',
arr: [1, 2, 3]
}
},
actions: {
changeState () {
this.counter++
this.foo = 'hello'
this.arr.push(4)
},
async setUser() {
const user = await Login()
this.foo = user.foo
}
})
storeToRefs
如果直接解构 store 数据,会导致失去响应式,所以要用到 storeToRefs 。
<script lang="ts" setup>
import { storeToRefs } from 'pinia'
import useCountStore from './store/counter'
const counterStore = useCountStore()
// 直接解构的话会造成数据失去响应式
// 解决:要用到 storeToRefs
const { count, double } = storeToRefs(counterStore)
</script>