Pinia 简介
Pinia 是 Vue 专属的最新状态管理库 ,是 Vuex 状态管理工具的替代品
Vue Pinia官方库
- 提供更加简单的API (去掉了 mutation )
- 提供符合,组合式风格的API (和 Vue3 新语法统一)
- 去掉了 modules 的概念,每一个 store 都是一个独立的模块
- 配合 TypeScript 更加友好,提供可靠的类型推断
Pinia 使用
手动添加
- 用你喜欢的包管理器安装
pinia
:
1 2
| npm install pinia yarn add pinia
|
- 创建一个 pinia 实例 (根 store) 并将其传递给应用:
1 2 3 4 5 6 7 8
| import { createApp } from 'vue' import { createPinia } from 'pinia' import App from './App.vue' const pinia = createPinia() const app = createApp(App) app.use(pinia).mount('#app')
|
定义
- 创建 src/store 目录,用于存放 store 数据
- 在数据文件中定义 store
- 与 Vue 组合式 API 的 setup 函数相似,我们可以传入一个函数,该函数定义了一些响应式属性和方法,并且返回一个带有我们想暴露出去的属性和方
ref()
就是 state
属性
computed()
就是 getters
function()
就是 actions
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import { defineStore } from "pinia"; import { computed, ref } from "vue";
export const useCounterStore = defineStore('counter', () => { const count = ref(100) const doubleCount = computed(() => count.value * 2) const addCount = () => {count.value++} const subCount = () => {count.value--} return { count, doubleCount, addCount, subCount } })
|
- 也有 Option Store 定义方式,这种非常麻烦难看懂,我不喜欢
- 你可以认为
state
是 store 的数据 (data
),getters
是 store 的计算属性 (computed
),而 actions
则是方法 (methods
)。
1 2 3 4 5 6 7 8 9 10 11
| export const useCounterStore = defineStore('counter', { state: () => ({ count: 0 }), getters: { double: (state) => state.count * 2, }, actions: { increment() { this.count++ }, }, })
|
- 在组件中调用 store
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| <script setup> import middleCom from '@/components/middleCom.vue' import bottomCom from '@/components/bottomCom.vue' import { useCounterStore } from '@/store/counter' const counter = useCounterStore() </script>
<template> <h1>顶层数据: {{ counter.count }}</h1> <h2>双倍结果: {{ counter.doubleCount }}</h2> <middleCom></middleCom> <bottomCom></bottomCom> </template>
<script setup> import { useCounterStore } from '@/store/counter'; const counter = useCounterStore() </script>
<template> <div> 中层数据 - {{ counter.count }} <button @click="counter.addCount">+1</button> </div> </template>
<script setup> import { useCounterStore } from '@/store/counter'; const counter = useCounterStore() </script>
<template> <div> 底层数据 - {{ counter.count }} <button @click="counter.subCount">-1</button> </div> </template>
|
action 异步实现
在 pinia 中,不再像 Vuex 那样需要考虑 mutations/actions 实现同步/异步,现在的 actions 都可以实现,同步实现在上面的代码中已经写了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import { defineStore } from "pinia"; import { ref } from "vue"; import axios from "axios";
export const useChannelStore = defineStore('channel', () => { const channelList = ref([]) const getList = async () => { const obj = await axios.get('http://geek.itheima.net/v1_0/channels') channelList.value = obj.data.data.channels console.log(channelList.value); } return { channelList, getList } })
|
storeToRefs 工具函数
在调用数据时,有时候需要解构库数据,如果直接解构会导致数据失去响应式特性
使用 storeToRefs 工具函数,可以辅助保持数据 (state+getter)的响应式解构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <script> import middleCom from '@/components/middleCom.vue' import bottomCom from '@/components/bottomCom.vue' import { storeToRefs } from 'pinia' import { useCounterStore } from '@/store/counter' import { useChannelStore } from '@/store/channel' const counter = useCounterStore() const channel = useChannelStore() const { count, doubleCount } = storeToRefs(counter) const { getList } = channel const { channelList} = storeToRefs(channel) </script>
<template> <h1>顶层数据: {{ count }}</h1> <h2>双倍结果: {{ doubleCount }}</h2> <middleCom></middleCom> <bottomCom></bottomCom> <div> <button @click="getList">获取列表</button> <ul> <li v-for="item in channelList" :key="item.id">{{ item.name }}</li> </ul> </div> </template>
|
Pinia 数据持久化插件
官方文档:https://prazdevs.github.io/pinia-plugin-persistedstate/zh/
- 选择喜欢的包管理器安装依赖:
1 2 3
| npm i pinia-plugin-persistedstate yarn add pinia-plugin-persistedstate pnpm i pinia-plugin-persistedstate
|
- 在 main.js 中,将插件添加到 pinia 实例上
1 2 3 4 5 6 7 8 9
| import { createApp } from 'vue' import { createPinia } from 'pinia' import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' import App from './App.vue' const pinia = createPinia() const app = createApp(App) pinia.use(piniaPluginPersistedstate) app.use(pinia).mount('#app')
|
- 创建 Store 时,将
persist
选项设置为 true
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import { defineStore } from "pinia"; import { computed, ref } from "vue"; export const useCounterStore = defineStore('counter', () => { const count = ref(100) const doubleCount = computed(() => count.value * 2) const addCount = () => {count.value++} const subCount = () => {count.value--} return { count, doubleCount, addCount, subCount } },{ persist: true })
|