likes
comments
collection
share

快速了解 Pinia (上)基础篇

作者站长头像
站长
· 阅读数 44

前言

Pinia是 Vue 生态的状态管理工具,由 Vue 官方团队成员打造,是事实上的Vuex 5Pinia最大的优点就是简单。以一个个独立的Store 为核心,摒弃了Vuex复杂的Mutations、同步和异步统一合并到Actions中等设计,配合优秀的Devtools,使用体验提升巨大。 本文分上下两篇,首先谈谈基本使用,接下来通过一个购物车案例对它有一个比较生动的认识。请配合 Pinia 官方文档 阅读。

一、初始化项目

本例采用Vite,在目录下新建一个Vite项目:

yarn cerate vite

一路选下去(记得是vue-ts),然后在新项目内安装Pinia依赖:

yarn add pinia

最后安装项目全部依赖,便可开始编写工作:

yarn install

二、将 Pinia 实例 挂载到 Vue 应用

在工作区下的main.ts,导包后创建实例,并用.use()挂载到当前App上:

// main.ts

import { createApp } from "vue";
import { createPinia } from "pinia";   // +

import "./style.css";
import App from "./App.vue";

const app = createApp(App);

//创建 pinia 实例                       // +
const pinia = createPinia();           // + 


app.use(pinia);                        // + 
app.mount("#app");

三、创建Store

在工作区目录下新建 Store/,用来放置所有的Store。 推荐一个 .ts 文件内只放一个Store

使用defineStore()创建并返回一个Store实例,接收两个参数

  1. name:string     `Store`的唯一 id ,Pinia 将用它来连接 `store``devtools`
  2. options:object  一个对象,内部规定了 state / acions / getters
    
  • state 类似 Vue 组件的data,本质是一个箭头函数。数据要定义在箭头函数的return {...}内。
    • 必须是函数:避免在服务端渲染时,交叉请求导致的数据状态污染
    • 必须是箭头函数:为了 TS 更好的类型推导
  • getters 类似 Vue 组件的computed,本质是一个对象。内部的函数如果想获取state内部值,需要声明参数state
  • actions 类似 Vue 组件的methods,本质是一个对象。内部的函数如果想获state内部值,需要使用this

最后记得把这个Pinia实例导出去

实例名一般为use Xxxx Store defineStore()name命名为xxxx

// src/store/index.ts

import { defineStore } from "pinia";

export const useMainStore = defineStore("main", {
  state: () => {
    return {
      count: 100,
      foo:"bar",
      arr:[1,2,3],
    };
  },
  
  getters: {
    // 参数 state 是可选的
    count10(state):number{
        console.log("getters !");
        return state.count+10;
    }
  },
  
  //action 不可用箭头函数定义
  actions: {
    changeState(num:number){
        this.count+=num;
        this.foo="fixed via Store-action"
        this.arr.push(8)
    }
  },
});

四、使用 store

1. 组件中导入store并实例化

// src/componet/HelloWorld.vue

import { useMainStore } from "../store/index";
import { storeToRefs } from "pinia";

//获得 Store 实例
const mainStore = useMainStore();

如果希望从store引用的数据是响应式的,即在本组件修改的state后能实时更新到store里,还需导入storeToRefs

2.响应式数据

出于响应式数据的目的,这样使用数据是错的:

const { count, foo } = mainStore;

因为这只是复制了一份数据,修改后并不能更新store状态。 正确用法是将解构出来的数据做 ref 响应式处理,如下:

const { count, foo, arr } = storeToRefs(mainStore);

3.在组件中访问、修改 state

  1. 方式一:直接访问 / 修改单个数据
const mainStore = useStore()

mainStore.count++
mainStore.foo = "hello"
mainStore.$reset()      // 重置回初始值

  1. 方式二:通过$patch()批量修改多个数据,并不是写法上的简便,而是为了性能上的优化
 mainStore.$patch({
    count: mainStore.count + 1,
    foo: "hello",
    arr: [...mainStore.arr, 4],    // 对于 array 等复杂结构,这样写法太低效
  })

但是上面这种做法也是有问题的:虽然可以通过直接赋值修改状态,但是对于像 Array 等数据类型,无法获取该对象,这意味着所有的类方法都不能使用。

  1. 方式三:$patch()参数内改用回调函数:
 mainStore.$patch((state) => {
    state.count++;
    state.foo = "hello";
    state.arr.push(5);           // 可以调用方法了
  });
  1. 方式四:当然了,逻辑再复杂的话,直接调用storeacions定义的函数即可。
// src/store/index.ts

export const useMainStore = defineStore("main", {
  ...

  actions: {
    changeState(num:number){
        this.count+=num;
        this.foo="fixed via Store-actions"
        this.arr.push(8)
    }
  },
});
// src/componet/HelloWorld.vue

<template>
  <div>{{mainStore.count}}</div>
  <div>{{mainStore.foo}}</div>
  <hr />
  <div>{{mainStore.count10}} 第1次调用 getters,调用count10()计算count+10</div>
  <div>{{mainStore.count10}} 第2次调用 getters,属性值不变,不再调用count10()计算</div>
  <div>{{mainStore.count10}} 第3次调用 getters,属性值不变,不再调用count10()计算</div>

  <p>
    <button @click="handleChangeCount">修改count</button>
  </p>
</template>


<script lang="ts" setup>
import { useMainStore } from "../store"; // 文件路径默认为 index ,不写也行
import { storeToRefs } from "pinia";

//获得 Store 实例
const mainStore = useMainStore();

const { count, foo, arr } = storeToRefs(mainStore);

const handleChangeCount = () => {
  //方式4:数据操作比较多时,可在 actions 封装函数,然后在普通组件中调用这些现成的函数
  mainStore.changeState(10);
};
</script>

4. getters(computed) 的特性

getters返回state中某个变量进行特定计算后的结果,这个结果是一个缓存值。如果该变量状态没发生变化,那么

getters无论调用多少次,值都不变。


本篇介绍了Pinia的基础使用,下篇将以一个购物车案例,将会有更生动的了解。

转载自:https://juejin.cn/post/7160934086314295303
评论
请登录