Pinia学习

135 阅读6分钟

Snipaste_2022-10-18_21-28-31.png

简洁明了,pinia就像是vuex的新版本。官网的解释:

Pinia 是 Vue 的存储库,它允许您跨组件/页面共享状态。

pinia的优点:

Vue2和Vue3都支持,这让我们同时使用Vue2和Vue3的小伙伴都能很快上手。

pinia中只有state、getter、action,抛弃了Vuex中的Mutation,Vuex中mutation一直都不太受小伙伴们的待见,pinia直接抛弃它了,这无疑减少了我们工作量。

pinia中action支持同步和异步,Vuex不支持

良好的Typescript支持,毕竟我们Vue3都推荐使用TS来编写,这个时候使用pinia就非常合适了

无需再创建各个模块嵌套了,Vuex中如果数据过多,我们通常分模块来进行管理,稍显麻烦,而pinia中每个store都是独立的,互相不影响。

体积非常小,只有1KB左右。

pinia支持插件来扩展自身功能。

支持服务端渲染。

思路分析

store

store简单来说就是数据仓库的意思,我们数据都放在store里面。当然你也可以把它理解为一个公共组件,只不过该公共组件只存放数据,这些数据我们其它所有的组件都能够访问且可以修改。 我们需要使用pinia提供的defineStore()方法来创建一个store,该store用来存放我们需要全局使用的数据。

创建store很简单,调用pinia中的defineStore函数即可,该函数接收两个参数:

name:一个字符串,必传项,该store的唯一id。

options:一个对象,store的配置项,比如配置store内的数据,修改数据的方法等等。

我们可以定义任意数量的store,因为我们其实一个store就是一个函数,这也是pinia的好处之一,让我们的代码扁平化了,这和Vue3的实现思想是一样的。使用store很简单,直接引入我们声明的useUsersStore 方法即可。

state

前面我们利用defineStore函数创建了一个store,该函数第二个参数是一个options配置项,我们需要存放的数据就放在options对象中的state属性内。在数据的读取上非常简单,我们只需要解构出即可使用,包括模版中。

  import { useUsersStore } from "../src/store/user";

  import { storeToRefs } from "pinia";

  const store = useUsersStore();

  const { name, age, sex } = store;

无论任何层级组件都可以轻松使用。修改时我们需要通过利用pinia的storeToRefs函数,将state中的数据变为了响应式。

  const { name, age, sex } = storeToRefs( store);

重置时直接使用 直接调用store的reset()方法即可。当我们想要批量修改多个属性时,pinia提供的patch方法。

getter

大家可以把getter想象成Vue中的计算属性,它的作用就是返回一个新的结果,就是处理state数据。使用时我们可以直接store.方法,具体可以参考下面的例子。 但是有时候我们需要在这一个getter方法中调用其它getter方法,这个时候如何调用呢? 其实很简单,我们可以直接在getter方法中调用this,this指向的便是store实例,所以理所当然的能够调用到其它getter。当然getter也可以接受我们传入参数进行计算操作。这些也同样可以参考下面的例子。

actions

actions属性值同样是一个对象,该对象里面也是存储的各种各样的方法,包括同步方法和异步方法。在需要用到的地方直接调用store中的actions方法即可。

与vuex比较

先来看官网描述:

Pinia 最初是为了探索 Vuex 的下一次迭代会是什么样子,结合了 Vuex 5 核心团队讨论中的许多想法。最终,我们意识到 Pinia 已经实现了我们在 Vuex 5 中想要的大部分内容,并决定实现它 取而代之的是新的建议。

与 Vuex 相比,Pinia 提供了一个更简单的 API,具有更少的规范,提供了 Composition-API 风格的 API,最重要的是,在与 TypeScript 一起使用时具有可靠的类型推断支持。

当我们通过vuex修改state时 , vuex中的流程是首先actions一般放异步函数,拿请求后端接口为例,当后端接口返回值的时候,actions中会提交一个mutations中的函数,然后这个函数对vuex中的状态(state)进行一个修改,组件中再渲染这个状态。

而当我们通过vuex修改state时,是直接修改的。

如果项目比较大,使用单一状态库,项目的状态库就会集中到一个大对象上,显得十分臃肿难以维护。所以Vuex就允许我们将其分割成模块(modules),每个模块都拥有自己state,mutations,actions...。而Pinia每个状态库本身就是一个模块。Pinia没有modules,如果想使用多个store,直接定义多个store传入不同的id即可。

demo

我用vue3+TS+pinia写了一个demo,大家可以本地跑起来。废话不多说,直接上代码,记得配置好vue3和ts。

在App.vue中(src\App.vue)

< template >

    < img alt= "Vue logo" src= "./assets/logo.png" />

    < p >姓名: {{ name }}</ p >

    < p >年龄: {{ age }}</ p >

    < p >性别: {{ sex }}</ p >

    < p >新年龄: {{ store. getAddAge( 1100) }}</ p >

    < p >调用其它getter: {{ store. getNameAndAge }}</ p >

    < button @ click=" changeName" >直接修改store更改姓名 </ button >

    < button @ click=" reset" >调用reset重置store数据 </ button >

    < button @ click=" patchStore" >调用patch批量修改数据 </ button >

    < button @ click=" saveName" >调用aciton更改姓名 </ button >

 

 

    <!-- 子组件 -->

    < Child ></ Child >

  </ template >

  < script setup lang= "ts" >

  import Child from "./Child.vue";

  import { useUsersStore } from "../src/store/user";

  import { storeToRefs } from "pinia";

  const store = useUsersStore();

  const { name, age, sex } = storeToRefs( store);

  const changeName = () => {

    store. name = "张三";

    console. log( store);

  };

  // 重置store

  const reset = () => {

    store. $reset();

  };

  // 批量修改数据

  const patchStore = () => {

    store. $patch({

      name : "张三",

      age : 100,

      sex : "女",

    });

  };

  // 调用actions方法

  const saveName = () => {

    store. saveName( "我是小猪");

  };

  </ script >

在Child.vue中( src\Child.vue )

< template >

    < h1 >我是child组件 </ h1 >

    < p >姓名: {{ name }}</ p >

    < p >年龄: {{ age }}</ p >

    < p >性别: {{ sex }}</ p >

    < button @ click=" changeName" >更改姓名 </ button >

  </ template >

  < script setup lang= "ts" >

  import { useUsersStore } from "./store/user";

  import { storeToRefs } from 'pinia';

  const store = useUsersStore();

  const { name, age, sex } = storeToRefs( store);

  const changeName = () => {

    store. name = "小猪";

  };

  </ script >

在main.ts中(src\main.ts)

import { createApp } from "vue";

import App from "./App.vue";

import { createPinia } from "pinia";

const pinia = createPinia();

const app = createApp( App);

app. use( pinia);

app. mount( "#app");

在user.ts中(src\store\user.ts)

import { defineStore } from "pinia";

  


// 第一个参数是应用程序中 store 的唯一 id

export const useUsersStore = defineStore( "users", {

  state : () => {

    return {

      name : "我我我",

      age : 22,

      sex : "男",

    };

  },

  getters : {

    getAddAge : ( state) => {

      return ( num: number) => state. age + num;

    },

    getNameAndAge() : string {

        return this. name + this. getAddAge( 0); // 调用其它getter

    }

  },

  actions : {

    saveName( name: string) {

      this. name = name;

    },

  },

});
该demo涵盖内容:

创建store,使用store。

创建state,使用state,添加state,读取state数据,修改state数据,重置state数据,批量修改state数据。

添加getter,使用getter,getter中调用其他getter,getter传参。

添加actions,使用actions。

总结

pinia大家学习起来也会感觉很轻松,没有vuex繁重。定义store,使用数据,修改数据,使用方法都变得非常轻松。大家都说,小项目拿pinia管理,大项目用vuex,可能工作开发中使用不到,但是可以学习它的思想。