介绍
跟 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// ornpm 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 } = storereturn {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()// 直接解构的话会造成数据失去响应式// 解决:要用到 storeToRefsconst { count, double } = storeToRefs(counterStore)</script>
