新状态管理工具Pinia

294 阅读4分钟

大家好,我是右子。

Vue3成为默认版后,Vuex的状态管理地位受到了Pinia的挑战。 推荐使用Pinia,因为Pinia确实太方便和简单了。

分享内容

  • Pinia的优势和安装
  • 使用Pinia的方式创建store和读取
  • 用简单的方法改变状态数据
  • Pinia改变状态数据的几种方式
  • Pinia中Actions的使用
  • Pinia中Getters的使用

Pinia的优势

Pinia是Vue生态里Vuex的代替者,是新一代Vue的状态管理库。

  • 可以对Vue2和Vue3做到很好的支持,也就是老项目也可以使用Pinia。
  • 抛弃了Mutations的操作,只有state、getters和actions,极大的简化了状态管理库的使用,让代码编写更加容易直观。
  • 不需要嵌套模块,符合Vue3的Composition api,让代码更加扁平化。
  • 完整的TypeScript支持,Vue3版本的一大优势就是对TypeScript的支持,所以Pinia也做到了完整的支持。
  • 代码更加简洁,可以实现很好的代码自动分割。在Vue2中写代码需要来回翻滚屏幕屏幕找变量,非常的麻烦,Vue3的Composition api完美了解决这个问题。 可以实现代码自动分割,pinia也同样继承了这个优点。

简单总结Pinia的优势就是,更加简洁的语法,完美支持Vue3的Composition api 和 对TypesCcript的完美支持。这些优势和尤雨溪的强烈推荐,个人觉得 Pinia 将成为最适合Vue3的状态管理库。

Pinia 的安装

安装Pinia状态管理库了。安装的方法依然是使用npm 来安装。

npm install pinia
# or with pnpm
pnpm install pinia

视频中使用了npm 来进行安装。安装完成后,可以到项目中的package.json文件中查看一下pinia的版本。

{
  "name": "pinia-cli",
  "version": "1.0.0",
  "scripts": {
  },
  "dependencies": {
    "pinia": "^2.0.13"
  }
}

你也可以指定pinia的安装版本,比如2.0.13

npm install pinia@2.0.13

引用Pinia

我们使用 import 引入。

// main.js
import { createPinia } from 'pinia';

引入后,通过 createPinia() 方法,得到pinia的实例和挂载到Vue根实例上。

// main.js
import { createApp } from 'vue';
import { createPinia } from 'pinia' ;
import App from './App.vue';

// 创建pinia 实例
const pinia = createPinia();
const app = createApp(App);
// 挂载到 Vue 根实例上
app.use(pinia);
app.mount('#root');

这样我们就在项目中引入了Pinia,也就是说我们可以在项目中使用它进行编程了。

创建store状态管理模块

引入Pinia后,就可以创建状态管理库了,也就是常说的Store。新建一个store文件夹,在文件夹内创建一个index.js文件,一般我们只做三件事。

  • 定义状态(state:()=> {})
  • 修改容器中的 state
  • 仓库中的 action 的使用

明确了之后,我们来编写代码。

import { defineStore } from 'pinia';

export const mainStore = defineStore('main',{
  state(){
    return {};
  },
  getters:{},
  actions:{}
});

写完这段代码,你会感觉这个很像一个Vue的组件,这也算是Pinia的一个优点。

  • defineStore()方法的第一个参数:相当于为容器起一个名字。
    • 注意:这里的名字必须唯一,不能重复。
  • defineStore()方法的第二个参数:可以简单理解为一个配置对象,里边是对store仓库的配置说明。
    • state:用来存储全局的状态的,这里边定义的,就可以是为SPA里全局的状态了。
    • getters:用来监视或者说是计算状态的变化的,有缓存的功能。
    • actions:对state里数据变化的业务逻辑,需求不同,编写逻辑不同。

我们在Store里定义一个State,我们这里就写hi Pinia.

const store = {
    state:()=>{
        return {
              projectName:'hi Pinia.',
              count: 0
        }
    }
}

这时候这个hi Pinia.就是全局的状态数据,是每个页面和组件都可以通过Pinia方法读取到的。

读取store中的数据

<template>
  <div>{{ store.projectName }}</div>
</template>

<script setup>
import { mainStore } from "@app/stores/index";
const store = mainStore();
console.log(store);
</script>

先引入mainStore,然后通过mainStore得到store实例,就可以在组件里调用store里定义的state数据状态了。

修改store中的数据

首先我们读取出数据,然后添加一个事件操作。

<template>
  <div>计数器:{{ store.count }}</div>
  <button @click="onCount"></button>
</template>

<script setup>
import { mainStore } from "@app/stores/index";
const store = mainStore();
console.log(store);

function onCount(){
    store.count = store.count+1;
};
</script>

看!这种改变状态数据的方法是非常方便的,要比Vuex简洁多了。可以看到当你点击按钮后,数据通过Pinia的状态管理,已经响应到页面中了。

结构的store数据还是响应式的吗?

当你结构了store,数据就不是响应式的了,但是有方法可以解决。

import { storeToRefs } from "pinia"; // pinia提供的响应式方法
import { mainStore } from "@app/stores/index";
const { count } = storeToRefs(mainStore());
console.log(store);

function onCount(){
    count = count+1;
};

使用 $patch 修改数据

如果你同时修改多条数据,建议使用$patch的方法。

<template>
  <div>计数:{{ store.count }}</div>
  <div>项目名:{{ store.projectName }}</div>
  <button @click="onChange"></button>
</template>

<script setup>
import { mainStore } from "@app/stores/index";
const store = mainStore();

function onChange(){
    store.$patch({ 
        count: store.count + 1, 
        projectName: store.projectName + '!'
    });
};
</script>

$patch可以传入一个对象作为参数,也可以传入一个函数作为参数使用,可以处理一些复杂的逻辑。

<template>
  <div>计数:{{ store.count }}</div>
  <div>项目名:{{ store.projectName }}</div>
  <button @click="onChange"></button>
</template>

<script setup>
import { mainStore } from "@app/stores/index";
const store = mainStore();

function onChange(){
    store.$patch((state)=>{ 
        state.count ++;
        state.projectName = state.projectName + '!';
    });
};
</script>

使用 actions 方法

还可以使用actions中定义函数处理数据,然后在组件里调用函数。

// path => store/index.js
import { defineStore } from 'pinia';

export const mainStore = defineStore('main',{
  state(){
    return {
        count: 0,
        projectName: "hi Pinia."
    };
  },
  getters:{},
  actions:{
      setStateChange(){ 
          this.count ++;
          this.projectName = "hi Pinia..."; 
      } 
  }
});
// path => app.vue
<template>
  <div>计数:{{ store.count }}</div>
  <div>项目名:{{ store.projectName }}</div>
  <button @click="onChange"></button>
</template>

<script setup>
import { mainStore } from "@app/stores/index";
const store = mainStore();

function onChange(){
    store.setStateChange();
};
</script>

使用 getterrs 方法

在getters里面编写一个方法,处理数据。

import { defineStore } from 'pinia';

export const mainStore = defineStore('main',{
  state(){
    return {
        count: 0,
        projectName: "hi Pinia."
    };
  },
  getters:{
      handlerCount(state){
          return state.projectName = "hello, new state management tools";
      }
  },
  actions:{}
});
<template>
  <div>计数:{{ store.handlerCount }}</div>
  <button @click="onChange"></button>
</template>

<script setup>
import { mainStore } from "@app/stores/index";
const store = mainStore();

function onChange(){
    store.count ++;
};
</script>

Pinia中的getters是有缓存特性的。

当数据改变时,getters会自动工作,对应的方法也会随着调用一次,清除以前的数据缓存。

总结

以上就是Pinia的使用方法,具体还可以参考Pinia官网进行学习。