什么是pinia
官网的解释:Pinia 是 Vue 的专属状态管理库,它允许您跨组件或页面共享状态。
实际上,Pinia 是 Vuex 的升级版,但为了尊重原作者,它被命名为 Pinia。因此,您可以简单地将其视为起到 Vuex 的作用。
为什么用pinia
上图展示了Vue的组件结构,其中Root是根组件,下面连接的是其子组件和子孙组件。
对于组件A,它有一个变量count和一个可以改变count值的函数。当执行setCount(20)时,count的值就会变成20。
现在有一个需求,即组件B和组件C也希望展示count的值,该怎么做呢?
一种方案是在根组件中创建 count 和 setCount,然后将它们作为参数传递给组件 A 以展示和修改,将 count 值传递给组件 B 和 C 以展示。
上述方案明显过于繁琐,通过中间参数传递值会使得代码冗余且容易出错。一旦某个组件展示不正确,则需要层层调试。
看看新的方案,我在组件之外单独维护一个 store 的状态块,里面记录了 count 的值以及能够操作 count 变化的 setCount 方法。然后将它下发到我需要使用的各个组件。对于组件 A,传递 count 和 setCount;对于组件 B 和 C,传递 count 用于显示。
这样做的优势有:
- 将数据和组件解耦。组件里的业务需要展示数据时,从
store中获取;需要修改数据时,触发store的方法。 - 将数据集中在一个地方,方便管理。一旦发现某个数据有误,可以很快地找到文件。
除了 Pinia 之外,其他状态管理库也有类似的优势:
-
Devtools支持- 追踪
actions、mutations的时间线 - 在组件中展示它们所用到的
Store - 让调试更容易的
Time travel
- 追踪
-
热更新
- 不必重载页面即可修改
Store - 开发时可保持当前的
State
- 不必重载页面即可修改
-
插件:可通过插件扩展
Pinia功能 -
为
JS开发者提供适当的TypeScript支持以及自动补全功能。 -
支持服务器端渲染。
pinia的使用
1、 初始化项目
执行 npm init vue@latest 命令,安装 Vue3 项目。之后输入以下内容:
✔ Project name: … pinia-learn
✔ Add TypeScript? … No
✔ Add JSX Support? … No
✔ Add Vue Router for Single Page Application development? … Yes
✔ Add Pinia for state management? … Yes
✔ Add Vitest for Unit Testing? … No
✔ Add an End-to-End Testing Solution? › No
? Add ESLint for code quality? › No
根据以下命令,安装完成后进入 pinia-learn 目录,执行 npm install 安装依赖,然后执行 npm run dev。在浏览器中访问 [http://localhost](http://localhost/):**5174**/ 打开页面。
2、安装pinia
yarn add pinia
npm install pinia
3、引入pinia
首先,通过 npm init vue@latest 安装一个基础的 Vue 项目。然后,按照以下方式修改 main.js 文件,引入 pinia 并使用 createApp 创建应用程序:
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const app = createApp(App)
app.use(createPinia())
app.mount('#app')
4、创建store
创建名为stores的文件夹,然后在其中创建名为counter.js的文件。
import { defineStore } from 'pinia'
export const useCounterStore = defineStore({
id: 'counter',
state: () => ({
count: 0,
}),
actions: {
increaseCount() {
this.count++
},
decreaseCount() {
this.count--
}
},
getters: {
doubleCount: state => state.count * 2
},
})
创建 store 的逻辑非常简单,只需调用 defineStore 创建一个 useCounterStore 并导出即可。defineStore 方法接受以下参数:
- id:唯一标识,必须传入。
Pinia将使用它连接store和devtools。 - state:存储
store的数据(data)。 - actions:定义了一些方法(methods),通过
actions可以让我们修改 state 的值。 - getters:
store的计算属性(computed),可以获取基于state生成的一些值。
5、使用store
App.vue
引入两个页面,分别展示主页和关于页面。
<template>
<div class="app">
<nav>
<RouterLink to="/">操作页</RouterLink> |
<RouterLink to="/about">展示</RouterLink>
</nav>
<RouterView />
</div>
</template>
<style>
.app {
text-align: center;
}
</style>
HomeView.vue
- 从
stores/counter中引入useCounterStore,创建storeCounter变量。 - 从
storeCounter获取count并在页面上显示。 - 创建两个按钮,加号按钮绑定
increaseCount方法,减号按钮绑定decreaseCount方法。
上述变量在我们创建 store 时都可以找到,大家可以对应查看。
<template>
<div class="home">
<div class="count">{{ storeCounter.count }}</div>
</div>
<div class="buttons">
<button @click="storeCounter.decreaseCount">-</button>
<button @click="storeCounter.increaseCount">+</button>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
import { useCounterStore } from '@/stores/counter';
const storeCounter = useCounterStore();
</script>
<style>
.count {
font-size: 60px;
margin: 0;
}
.buttons button {
font-size: 40px;
margin: 10px;
}
</style>
之后我们可以看到如下的页面。当点击加号或减号时,上面的count会发生相应的变化。
AboutView.vue
在这个页面,我们主要测试在HomeView组件下改变的count是否可以同步变化。
我们引入storeCount,并显示它的属性count。然后操作HomeView的按钮,切换到展示页面查看数据。
同时,我们给展示的按钮绑定了increaseCount事件。操作之后,回到操作页面,数值也会同步变化。
<template>
<div class="about">
<button @click="storeCounter.increaseCount">
{{ storeCounter.count }}
</button>
</div>
</template>
<script setup>
import { useCounterStore } from '../stores/counter';
const storeCounter = useCounterStore();
</script>
<style>
button {
font-size: 50px;
margin: 10px;
}
</style>
总结
相对来说,Pinia 的使用方法较少。简单来说,可以将其理解为创建了一个文件和变量,其中包含了需要的变量和方法。然后将这些值导出,在需要使用的组件中引入即可。
参考资料