了解Pinia状态管理

331 阅读4分钟

Pinia.js 是 Vue.js 官方推荐的新一代状态管理库,由 Vue.js团队中成员所开发的(也被认为是下一代的 Vuex,即 Vuex5.x),它提供了非常简洁和直观的 API,可以极大地提高我们管理应用状态的效率。

Pinia 的优势

  • 完整的 typescript 的支持;
  • 足够轻量,压缩后的体积只有1.6kb;
  • 去除 mutations,只有 state,getters,actions;
  • actions 支持同步和异步;
  • 没有模块嵌套,只有 store 的概念,每个模块是一个 Store,store 之间可以自由使用,更好的代码分割;
  • 无需手动添加 store,store 一旦创建便会自动添加;
  • 直观的 Devtools,可以看到每个 State 的变化

安装

npm install pinia --save

创建store

新建 src/store 目录并在其下面创建 index.js,导出 store

import { createPinia } from 'pinia';

const store = createPinia();

export default store;

在 main.js 中引入并使用。

import { createApp } from 'vue'
import App from './App.vue'
import store from './store';

const app = createApp(App)

app.use(store)

app.mount('#app')

可以通过 app.config.globalProperties.$pinia 访问 Pinia 实例。

Option Store(选项式Store)

与 Vue 的选项式 API 类似,我们也可以传入一个带有 stateactions 与 getters 属性的 Option 对象(废弃了Mutations)

使用 defineStore API 定义 Store: 在 src/store/modules 下面创建一个user.js

import { defineStore } from 'pinia'  
  
export const useUserStore = defineStore('user', {  
  
  // state  
  state() => {  
    return {  
      counter0  
    }  
  },  
  
  // getters  
  getters: {  
    doubleCount(state) {  
      return state.counter * 2  
    }  
  },  
  
  // actions  
  actions: {  
    increment() {  
      this.counter++   
    },
    updateCounter() {  
      this.counter+=2   
    }  
  }  
})
  • 接收唯一 ID 作为第一个参数
  • state、getters、actions 定义方式与 Vue 组件类似
  • 可以直接通过 this 访问状态

使用

获取 state

<template>  
  <div>{{ userStore.counter }}</div>  
</template>  
  
<script setup>  
import { useUserStore } from '@/store/modules/user'  
  
const userStore = useUserStore()  
</script>

也可以结合 computed 获取。

const counter = computed(() => userStore.counter)

state 也可以使用解构,但使用解构会使其失去响应式,这时候可以用 pinia 的 storeToRefs

import { storeToRefs } from 'pinia'  
const { counter } = storeToRefs(userStore)

修改 state

可以像下面这样直接修改 state

userStore.counter = 2

但一般不建议这么做,建议通过 actions 去修改 state,action 里可以直接通过 this 访问。

userStore.updateCounter()

Getters

const double = userStore.doubleCount

Actions

1.异步Action

action 可以像写一个简单的函数一样支持 async/await 的语法,让你愉快的应付异步处理的场景。

export const useUserStore = defineStore('user', { 
  actions: {  
    async login(account, pwd) {  
      const { data } = await api.login(account, pwd)  
      return data  
    }  
  }  
})

action 间相互调用

action 间的相互调用,直接用 this 访问即可。

export const useUserStore = defineStore({  
  id'user',  
  actions: {  
    async login(account, pwd) {  
      const { data } = await api.login(account, pwd)  
      this.setData(data) // 调用 action 另一个的方法  
      return data  
    },  
    setData(data) {  
      console.log(data)  
    }  
  }  
})

在 action 里调用其他 store 里的 action 也比较简单,引入对应的 store 后即可访问其内部的方法了。

import { useAppStore } from './app'  
export const useUserStore = defineStore('user', {   
  actions: {  
    async login(account, pwd) {  
      const { data } = await api.login(account, pwd)  
      const appStore = useAppStore()  
      appStore.setData(data) // 调用 app store 里的 action 方法  
      return data  
    }  
  }  
})  
复制代码  
// src/store/app.js  
  
export const useAppStore = defineStore('app', {  
  actions: {  
    setData(data) {  
      console.log(data)  
    }  
  }  
})

数据持久化

插件 pinia-plugin-persist 可以辅助实现数据持久化功能。

  • 安装pinia-plugin-persist
npm i pinia-plugin-persist --save
  • 使用pinia-plugin-persist
// src/store/index.js  
  
import { createPinia } from 'pinia'  
import piniaPluginPersist from 'pinia-plugin-persist'  
  
const store = createPinia()  
store.use(piniaPluginPersist)  
  
export default store

接着在对应的 store 里开启 persist 即可。

import { defineStore } from 'pinia'  
  
export const useUserStore = defineStore('user', {  
  
  // state  
  state() => {  
    return {  
      counter0  
    }  
  },  
  
  // getters  
  getters: {  
    doubleCount(state) {  
      return state.counter * 2  
    }  
  },  
  
  // actions  
  actions: {  
    increment() {  
      this.counter++   
    },
    updateCounter() {  
      this.counter+=2   
    }  
  },
  
  // 开启数据缓存  
  persist: {  
    enabledtrue  
  }
})

数据默认存在 sessionStorage 里,并且会以 store 的 id 作为 key。

  • 自定义 key

也可以在 strategies 里自定义 key 值,并将存放位置由 sessionStorage 改为 localStorage。

persist: {  
  enabled: true,  
  strategies: [  
    {  
      key: 'my_user',  
      storage: localStorage,  
    }  
  ]  
}
  • 持久化部分 state

默认所有 state 都会进行缓存,可以通过 paths 指定要持久化的字段,其他的则不会进行持久化

state: () => {  
  return {  
    name: '张三',  
    age: 18,  
    gender: '男'  
  }    
},  
  
persist: {  
  enabled: true,  
  strategies: [  
    {  
      storage: localStorage,  
      paths: ['name''age']  
    }  
  ]  
}

上面我们只持久化 name 和 age,并将其改为localStorage, 而 gender 不会被持久化,如果其状态发送更改,页面刷新时将会丢失,重新回到初始状态,而 name 和 age 则不会

Setup Store (Composition API)

存在另一种定义 store 的可用语法。与 Vue 组合式 API 的 setup 函数 相似,我们可以传入一个函数,该函数定义了一些响应式属性和方法,并且返回一个带有我们想暴露出去的属性和方法的对象。

export const useUserStore = defineStore('user'() => {  
  const count = ref(0)  
  function increment() {  
    count.value++  
  }  
  
  return { count, increment }  
})

在 Setup Store 中:

  • ref() 就是 state 属性
  • computed() 就是 getters
  • function() 就是 actions

Setup store 比 Option Store 带来了更多的灵活性,因为可以在一个 store 内创建侦听器,并自由地使用任何组合式函数。不过,请记住,使用组合式函数会让 SSR 变得更加复杂。

参考链接1

参考链接2