Vue3 核心知识点之 - Pinia

一、 Pinia 是什么?

        Pinia 是一个专为 Vue.js 设计的状态管理库。它提供了一种简单且优雅的方式来管理应用程序的状态,并且与 Vue 3 生态系统无缝集成。Pinia 的设计目标是提供一种现代化的状态管理解决方案,使得开发者能够更轻松地管理应用程序中的状态,并且在面对大型应用或复杂状态管理需求时保持高效。

        有关状态的概念以及与Vuex之间的对比可参考: Vue核心知识点 - VueX-CSDN博客

二、Pinia 核心知识点

官网:简介 | Pinia

三、Pinia 如何在项目中使用(以 vue3 组合式api + ts 举例)

步骤一、下载 pinia

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

步骤二、创建 Pinia Store

// src/store/counter.ts
import { defineStore } from "pinia";

export const useCounterStore = defineStore("counter", () => {
  // ref变量 → state 属性
  const count = ref(0);
  // computed计算属性 → getters
  const double = computed(() => {
    return count.value * 2;
  });
  // function函数 → actions
  function increment() {
    count.value++;
  }

  return { count, double, increment };
});

步骤三、在 main.ts 全局注册 Pinia

import { createApp } from 'vue'

import App from './App.vue'

// 导入 createPinia 函数
import { createPinia } from 'pinia';

const app = createApp(App)
// 全局注册 pinia
app.use(createPinia())
app.mount('#app')

 步骤四、组件中使用 Pinia Store

父组件

<script setup lang="ts">
import HelloWorld from '@/components/HelloWorld.vue'

// 导入 useCounterStore 函数
import { useCounterStore } from '@/stores/counter'
// 创建 counterStore 实例
const counterStore = useCounterStore()
</script>

<template>
  <div class="father">
    <p>这是父组件</p>
    <p>count: {{ counterStore.count }}</p>
    <p>double: {{ counterStore.double }}</p>
    <button @click="counterStore.increment">count++</button>
  </div>
  <HelloWorld/>
</template>

<style lang="scss" scoped>
</style>
<style lang="scss" scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
  transition: filter 300ms;
  background-color: $bg-color;
}
</style>

子组件

<script setup lang="ts">
// 导入 useCounterStore 函数
import { useCounterStore } from '@/stores/counter'
// 创建 counterStore 实例
const counterStore = useCounterStore()
</script>

<template>
  <div class="son">
    <p>这是子组件</p>
    <p>count: {{ counterStore.count }}</p>
    <p>double: {{ counterStore.double }}</p>
    <button @click="counterStore.subtraction">count--</button>
  </div>
</template>


<style lang="scss" scoped>
  .son{
    height: 500px;
    width: 500px;
    border: 1px red solid;
  }
</style>

点击父组件 count ++ 按钮页面变化

点击子组件 count -- 按钮页面变化

四、持久化 store 的状态(以@usevue/core举例)

下载 @usevue/core

npm i @vueuse/core

使用 useStorage 函数 定义持久化存储的数据

修改 store/couter.ts 代码

// src/store/counter.ts
import { defineStore } from "pinia";
// 导入 useStorage 函数
import { useStorage } from '@vueuse/core'
export const useCounterStore = defineStore("counter", () => {

  // ref变量 → state 属性
  // 使用 useStorage(存储名称, 初始值, 存储方式)
  // 存储方式不给默认是localStorage
  const count = useStorage('count', 0);

  // computed计算属性 → getters
  const double = computed(() => {
    return count.value * 2;
  });

  // function函数 → actions
  function increment() {
    count.value++;
  };

  function subtraction() {
    count.value--;
  };

  return { count, double, increment, subtraction };
});

重新运行代码

可以看到 localstorage 存储 count 数据

为 store/couter.ts 代码 useStorage 函数添加第三个参数 sessionStorage、并重新运行代码

const count = useStorage('count', 0, sessionStorage);

五、注意事项

1、直接通过对象建构获取的状态不是响应式的

官网代码: 定义 Store | Pinia

<script setup>
import { useCounterStore } from '@/stores/counter'
const store = useCounterStore()
// ❌ 这将不起作用,因为它破坏了响应性
// 这就和直接解构 `props` 一样
const { name, doubleCount } = store
name // 将始终是 "Eduardo"
doubleCount // 将始终是 0
setTimeout(() => {
  store.increment()
}, 1000)
// ✅ 这样写是响应式的
// 💡 当然你也可以直接使用 `store.doubleCount`
const doubleValue = computed(() => store.doubleCount)
</script>

 2、确保 pinia 实例被激活、才能使用 store

官网代码: 在组件外使用 store | Pinia

import { useUserStore } from '@/stores/user'
import { createApp } from 'vue'
import App from './App.vue'

// ❌  失败,因为它是在创建 pinia 之前被调用的
const userStore = useUserStore()

const pinia = createPinia()
const app = createApp(App)
app.use(pinia)

// ✅ 成功,因为 pinia 实例现在激活了
const userStore = useUserStore()
import { createRouter } from 'vue-router'
const router = createRouter({
  // ...
})

// ❌ 由于引入顺序的问题,这将失败
const store = useStore()

router.beforeEach((to, from, next) => {
  // 我们想要在这里使用 store
  if (store.isLoggedIn) next()
  else next('/login')
})

router.beforeEach((to) => {
  // ✅ 这样做是可行的,因为路由器是在其被安装之后开始导航的,
  // 而此时 Pinia 也已经被安装。
  const store = useStore()

  if (to.meta.requiresAuth && !store.isLoggedIn) return '/login'
})

  • 13
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值