Vue3之状态管理器(Pinia)详解及使用方式

 更新时间:2024年03月11日 11:02:38   作者:明天也要努力  
这篇文章主要介绍了Vue3之状态管理器(Pinia)详解及使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

注意:本文项目使用脚手架为 Vite;

1. 前言

Pinia 对比 Vuex

  • Pinia 同时支持 Vue2 以及 Vue3 ,这让同时使用两个版本的小伙伴更容易上手;
  • Pinia 中只存在 State,getter,action,剔除掉了 Vuex 中的 Mutation 及 Module;
  • Pinia 中的 action 可同时支持同步任务、异步任务;
  • 更友好的支持了 TypeScript ,无需创建自定义复杂包装器来支持 TypeScript,所有内容都是类型化的,并且 API 的设计方式尽可能利用 TS 类型推断;
  • Pinia 在修改状态的时候不需要通过其他 api,如:vuex 需通过 commit,dispatch 来修改,所以在语法上比 vuex 更容易理解和使用灵活;
  • 由于去除掉了 Module ,无需再创建各个模块嵌套了。Vuex 中,如果数据过多,通常会通过划分模块来进行管理,而 Pinia 中,每个 Store 都是独立的,互不影响;
  • 支持服务端渲染;

2. 安装及引入

yarn add pinia
// 或者使用 npm
npm install pinia

安装完 Pinia 包之后,需要在 main.js 文件中导入 createPinia 函数并将 Pinia 插件与 Vue 应用程序绑定:

import { createApp } from 'vue';
import App from './App.vue';
// 引入 createPinia 函数
import { createPinia } from 'pinia';

const app = createApp(App)
// 使用 createPinia() 来创建 Pinia(根存储),并应用到整个应用中
app.use(createPinia());
app.mount('#app');

使用 createPinia() 函数创建并初始化 Pinia 插件实例,将其与 Vue 应用程序绑定使用 app.use(pinia)。

至此,我们就可以使用Pinia 来管理 Vue 应用程序的状态了。

最后,在 src 文件下创建一个 store 文件夹,并添加 store.js 文件。

3. Pinia的使用Store

Store

是使用 defineStore() 定义的,并且它需要一个唯一名称,作为第一个参数传递。

这个名字 ,也被用作 id 是必须传入的, Pinia 将用它来连接 store 和 devtools。

将返回的函数命名为 use… 是跨可组合项的约定,以使其符合使用习惯。

State

State 是 store 中存储数据的地方。

通过定义 State,可以在 store 的任何位置访问和修改数据。

// store/store.js
import { defineStore } from 'pinia';

export const useMainStore = defineStore('main',{
  state: () => {
    return {
      count:0
    }
  }
})
// views/home.vue
<template>
  <div class="count">state:{{mainStore.count}}</div>
  <div class="btnWrap">
    <button  @click="resetStore">重 置</button>
  </div>
</template>

<script setup>
  import {useMainStore} from '@/store/store.js';

  const mainStore = useMainStore();
  console.log(mainStore.count) // 0

  const resetStore = () => {
    mainStore.$reset()
  }
</script>

效果:

Getters

Getter 用来获取从 state 派生的数据,类似于 Vue 组件中的 computed 计算属性。

可通过 defineStore() 中的 getters 属性来定义它们。

推荐使用箭头函数,并且它将接收 state 作为第一个参数:

export const useStore = defineStore('main', {
  state: () => ({
    count: 0,
  }),
  getters: {
    doubleCount: (state) => state.count * 2,
  },
})

Actions

Action 相当于组件中的方法。

它可以通过 defineStore() 中的 actions 属性来定义;

Action 是一种将异步操作封装在 store 中的方式,它是一个可被调用的函数,也可接收参数并修改 store 中的状态。

import { defineStore } from 'pinia'

export const myStore = defineStore('myStore',{ 
  state: () => ({
    message: 'Hello',
  }),
  actions: {
    async fetchMessage() {
      const res = await fetch('http://127.0.0.1:5173/message')
      this.message = res.message
    },
  },
})

4. 示例完整代码

4.1 选项式写法

// store/store.js
import { defineStore } from 'pinia';
import axios from 'axios';

export const useMainStore = defineStore('main',{
  state: () => {
    return {
      count:0,
      count2:0,
      list:[],
    }
  },
  getters:{
    doubleCount(){
      return this.count*2;
    }
  },
  actions:{
    add(){
      this.count++;
    },
    update(val){
      this.count = val.value;
    },
    add2(){
      this.count2++;
    },
    // 异步
    async getList(){
      const res = await axios.get('https://api.oioweb.cn/api/common/history');
      if(res.data.code == 200){
        this.list = res.data.result || [];
      }
    },
  }
})

在组件中使用

<template>
  <div class="count">state:{{mainStore.count}}</div>
  <div class="count">getters:{{mainStore.doubleCount}}</div>
  <div class="btnWrap">
    <button @click="resetStore">重 置</button>
    <button @click="addCount">增 加</button>
    <button @click="updateCount">更新至100</button>
  </div>
  <hr/>
  <div class="count">state:{{count2}}</div>
  <div class="btnWrap">
    <button @click="add2">增 加</button>
  </div>
  <hr/>
  <h3>历史上的今天</h3>
  <ul class="list">
    <li 
      v-for="(item,index) in mainStore.list"
      :key="index">
      {{item.year}}年 - {{item.title}}
    </li>
  </ul>
</template>
<script setup>
  import {useMainStore} from '@/store/store.js';
  import {onMounted,ref} from 'vue';
  import {storeToRefs} from 'pinia';

  const mainStore = useMainStore();
  const {count2} = storeToRefs(mainStore);
  const {add2} = mainStore;
  console.log(mainStore)

  const number = ref(100);

  const resetStore = () => {
    mainStore.$reset();
  }

  const addCount = () => {
    mainStore.add();
  };

  const updateCount = () => {
    mainStore.update(number);
  }

  onMounted(() => {
    mainStore.getList();
  })
</script>

效果:

分别触发 add2 两次,addCount、getList 一次后的效果

4.2 组合式写法

在组合式 API 中:

  • ref() 相当于 state 属性;
  • computed() 相当于 getters;
  • function() 相当于 actions;
// store/count.js
import { defineStore } from 'pinia';
import {computed, ref} from 'vue';
import axios from 'axios';

// 第一个参数是应用中 Store 的唯一 ID
export const useCountStore = defineStore('count',() => {
  // state
  const count = ref(0);
  const count2 = ref(0);
  const list = ref([]);

  // getter 
  const doubleCount = computed(() => {
    return count.value*2
  })

  // 同步action 
  const add = () => {
    count.value++;
  }
  const update = (val) =>{
    count.value = val.value;
  }
  const add2 = () => {
    count2.value++;
  }

  // 异步action 
  const getList = async () => {
    const res = await axios.get('https://api.oioweb.cn/api/common/history');
    if(res.data.code == 200){
      list.value = res.data.result || [];
    }
  }

  return{
    count,
    count2,
    doubleCount,
    list,
    add,
    update,
    add2,
    getList,
  }
})

在组件中使用

<template>
  <div class="count">state:{{countStore.count}}</div>
  <div class="count">getters:{{countStore.doubleCount}}</div>
  <div class="btnWrap">
    <button @click="resetStore">重 置</button>
    <button @click="addCount">增 加</button>
    <button @click="updateCount">更新至100</button>
  </div>
  <hr/>
  <div class="count">state:{{count2}}</div>
  <div class="btnWrap">
    <button @click="add2">增 加</button>
  </div>
  <hr/>
  <h3>历史上的今天</h3>
  <ul class="list">
    <li 
      v-for="(item,index) in countStore.list"
      :key="index">
      {{item.year}}年 - {{item.title}}
    </li>
  </ul>
</template>
<script setup>
  import {useCountStore} from '@/store/count.js';
  import {onMounted,ref} from 'vue';
  import {storeToRefs} from 'pinia';

  const countStore = useCountStore();
  const {count2} = storeToRefs(countStore);
  const {add2} = countStore;
  console.log(countStore)

  const number = ref(100);

  const resetStore = () => {
    countStore.$reset();
  }

  const addCount = () => {
    countStore.add();
  };
  const updateCount = () => {
    countStore.update(number);
  }
  onMounted(() => {
    countStore.getList();
  })
</script>

效果:

分别触发 add2 两次,addCount、getList 一次后的效果

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Vue集成Iframe页面的方法示例

    Vue集成Iframe页面的方法示例

    这篇文章主要介绍了Vue集成Iframe页面的方法示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-12-12
  • vue中echarts关系图动态增删节点以及连线方式

    vue中echarts关系图动态增删节点以及连线方式

    这篇文章主要介绍了vue中echarts关系图动态增删节点以及连线方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • VUE3中watch监听使用实例详解

    VUE3中watch监听使用实例详解

    watch函数用来侦听特定的数据源,并在回调函数中执行副作用,下面这篇文章主要给大家介绍了关于VUE3中watch监听使用的相关资料,需要的朋友可以参考下
    2022-06-06
  • vue 注册组件的使用详解

    vue 注册组件的使用详解

    Vue.js的组件的使用有3个步骤:创建组件构造器、注册组件和使用组件。这篇文章主要介绍了vue 注册组件的使用,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2018-05-05
  • vue子组件设计provide和inject理解使用

    vue子组件设计provide和inject理解使用

    这篇文章主要为大家介绍了vue子组件设计provide和inject理解及使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • Vue路由钩子之afterEach beforeEach的区别详解

    Vue路由钩子之afterEach beforeEach的区别详解

    这篇文章主要介绍了Vue路由钩子 afterEach beforeEach区别 ,vue-router作为vue里面最基础的服务,学习一段时间,对遇到的需求进行一些总结。需要的朋友可以参考下
    2018-07-07
  • vue项目中使用iconfont方式

    vue项目中使用iconfont方式

    这篇文章主要介绍了vue项目中使用iconfont方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-07-07
  • Vue+Mockjs模拟curd接口请求的示例详解

    Vue+Mockjs模拟curd接口请求的示例详解

    这篇文章主要介绍了Vue+Mockjs模拟curd接口请求的示例详解,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • Vue开发Sort组件代码详解

    Vue开发Sort组件代码详解

    这篇文章主要介绍了Vue开发Sort组件,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2021-10-10
  • 在vue中实现表单验证码与滑动验证功能的代码详解

    在vue中实现表单验证码与滑动验证功能的代码详解

    在Web应用程序中,表单验证码和滑动验证是常见的安全机制,用于防止恶意攻击和机器人攻击,本文将介绍如何使用Vue和vue-verify-code库来实现表单验证码和滑动验证功能,需要的朋友可以参考下
    2023-06-06

最新评论