10分钟入门pinia

483 阅读4分钟

什么是pinia

官网的解释:PiniaVue 的专属状态管理库,它允许您跨组件或页面共享状态。

实际上,PiniaVuex 的升级版,但为了尊重原作者,它被命名为 Pinia。因此,您可以简单地将其视为起到 Vuex 的作用。

为什么用pinia

Pasted image 20230411160336.png

上图展示了Vue的组件结构,其中Root是根组件,下面连接的是其子组件和子孙组件。

对于组件A,它有一个变量count和一个可以改变count值的函数。当执行setCount(20)时,count的值就会变成20。

现在有一个需求,即组件B和组件C也希望展示count的值,该怎么做呢?

Pasted image 20230411163650.png

一种方案是在根组件中创建 countsetCount,然后将它们作为参数传递给组件 A 以展示和修改,将 count 值传递给组件 B 和 C 以展示。

上述方案明显过于繁琐,通过中间参数传递值会使得代码冗余且容易出错。一旦某个组件展示不正确,则需要层层调试。

Pasted image 20230411164319.png

看看新的方案,我在组件之外单独维护一个 store 的状态块,里面记录了 count 的值以及能够操作 count 变化的 setCount 方法。然后将它下发到我需要使用的各个组件。对于组件 A,传递 countsetCount;对于组件 B 和 C,传递 count 用于显示。

这样做的优势有:

  • 将数据和组件解耦。组件里的业务需要展示数据时,从 store 中获取;需要修改数据时,触发 store 的方法。
  • 将数据集中在一个地方,方便管理。一旦发现某个数据有误,可以很快地找到文件。

除了 Pinia 之外,其他状态管理库也有类似的优势:

  • Devtools 支持

    • 追踪 actionsmutations 的时间线
    • 在组件中展示它们所用到的 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? › NoAdd ESLint for code quality? › No 

根据以下命令,安装完成后进入 pinia-learn 目录,执行 npm install 安装依赖,然后执行 npm run dev。在浏览器中访问 [http://localhost](http://localhost/):**5174**/ 打开页面。

Pasted image 20230411171620.png

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() => ({
  count0,
 }),
 actions: {
  increaseCount() {
   this.count++
  },
  decreaseCount() {
   this.count--
  }
 },
 getters: {
  doubleCountstate => state.count * 2
 },
})

创建 store 的逻辑非常简单,只需调用 defineStore 创建一个 useCounterStore 并导出即可。defineStore 方法接受以下参数:

  • id:唯一标识,必须传入。Pinia 将使用它连接 storedevtools
  • 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

  1. stores/counter 中引入 useCounterStore,创建 storeCounter 变量。
  2. storeCounter 获取 count 并在页面上显示。
  3. 创建两个按钮,加号按钮绑定 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-size60px;
  margin0;
}
.buttons button {
  font-size40px;
  margin10px;
}
</style>

之后我们可以看到如下的页面。当点击加号或减号时,上面的count会发生相应的变化。

Untitled.png

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-size50px;
  margin10px;
}
</style>

Pasted image 20230411172804.png

总结

相对来说,Pinia 的使用方法较少。简单来说,可以将其理解为创建了一个文件和变量,其中包含了需要的变量和方法。然后将这些值导出,在需要使用的组件中引入即可。

参考资料

zhuanlan.zhihu.com/p/533233367

pinia.vuejs.org/zh/core-con…