神奇的Vue3 - Pinia

文章详细介绍了Vue3中的Pinia库,强调了其与Vuex相比的简单性、直观性、响应式设计、模块化和TypeScript支持,推荐作为Vue3新项目的状态管理首选。
摘要由CSDN通过智能技术生成

神奇的Vue3

第一章 神奇的Vue3—基础篇



前言(为什么选择Pinia而不是Vuex)

  • 简单性和直观性:Pinia 的 API 更简单、更直观,使得使用存储变得轻而易举。另外Pinia 的结构与Vue的Options API 类似,因此更容易上手。
  • 响应式状态管理Pinia 的状态可以直接在操作中进行更新,从而减少了冗余代码。与 Vuex 不同,Pinia 不再需要显式的提交mutation。
  • 模块化设计: Pinia 是模块化设计的,允许创建多个存储库,这些存储库可以直接在需要它们的组件中导入。这样可以更好地进行代码拆分,并提供更好的TypeScript 推断。
  • 开发者工具支持: Pinia 具有内置的开发者工具支持,与 Vuex 的开发者工具类似,可以更好地调试和跟踪状态的变化。
  • TypeScript 支持: Pinia 提供了更好的 TypeScript 支持,使得开发过程更加轻松。

总的来说,Pinia 提供了更简单、更直观的 API,更好的模块化设计以及更好的 TypeScript 支持,使得它成为 Vue 3 应用程序的首选状态管理库。当然,对于已经在使用 Vuex 的项目来说,迁移到 Pinia 可能需要一些工作,但对于新项目来说,Pinia 是一个更现代化、更简单的选择。


一、Pinia是什么?

Pinia 是一个用于 Vue 3 的状态管理库,旨在提供简单而强大的方式来管理应用程序的状态。它建立在 Vue 3 的响应性 API 之上,为大型应用程序中复杂状态的管理提供了简单而灵活的架构。Pinia 提供了一种存储模式,允许定义用于管理特定应用程序状态的数据存储。这使得组织应用程序状态变得简单,并且可以轻松地在组件之间共享状态。

二、使用步骤

1.引入Pinia

在项目中设置和安装 Pinia

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

2.创建一个 Pinia 实例并将其注册到 Vue 应用中:

代码如下(示例):

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

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

app.use(pinia)
app.mount('#app')

3.创建存储库(Store):

  • 在存储库文件夹内创建一个新文件,例如 counter.ts。
  • 在文件中导入 defineStore 和 ref:
import { ref } from 'vue';
import { defineStore } from 'pinia';
  • 使用 defineStore 创建存储库实例,并按照 Pinia 的命名约定命名存储库:
// 你可以任意命名 `defineStore()` 的返回值,但最好使用 store 的名字,同时以 use 开头且以 `Store` 结尾。
// (比如 `useUserStore`,`useCartStore`,`useProductStore`)
// 第一个参数:是你的应用中 Store 的唯一 ID。
// 第二个参数:可接受两类值:Setup 函数或 Option 对象。
export const useCounterStore = defineStore("counter", () => {
  // 在此定义状态、getter 和 action
  return {};
});

4.创建Store的两种语法

(1)Option Store

与 Vue 选项式 API(Option API) 类似,我们也可以传入一个带有 stateactionsgetters 属性的 Option 对象

  • state 是 store 的数据 (data)
  • getters 是 store 的计算属性 (computed)
  • actions 是方法 (methods)。
export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  getters: {
    double: (state) => state.count * 2,
  },
  actions: {
    increment() {
      this.count++
    },
  },
})

(2)Setup Store

与 Vue 组合式 API(Composition API)setup 函数 相似,我们可以传入一个函数,该函数定义了一些响应式属性和方法,并且返回一个带有我们想暴露出去的属性和方法的对象。

  • ref() 就是 state 属性
  • computed() 就是 getters
  • function() 就是 actions

注意,要让 pinia 正确识别 state,必须在 setup store 中返回 state 的所有属性

export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const doubleCount = computed(() => count.value * 2)
  function increment() {
    count.value++
  }

  return { count, doubleCount, increment }
})

5.使用 Store

我们在使用 <script setup> 调用 useStore()(或者使用 setup() 函数,像所有的组件那样) 之前,store 实例是不会被创建的:

store 被实例化后,可以直接访问在 storestategettersactions 中定义的任何属性

<script setup>
import { useCounterStore } from '@/stores/counter'
// 可以在组件中的任意位置访问 `store` 变量
const store = useCounterStore()
console.log(store);
</script>

三、Store核心

1. State

state 被定义为一个返回初始状态的函数

import { defineStore } from 'pinia'

interface UserInfo {
  name: string
  age: number
}
const useStore = defineStore('storeId', () => {
	// 箭头函数可以进行完整类型推理,推荐使用
	// 去掉return省略写法:
	// state: () => ({})
	state: () => {
		return {
			// 所有这些属性都将自动推断出它们的类型
			count: 0,
			name: 'Eduardo',
			isAdmin: true,
			// 用于初始化空列表
			userList: [] as UserInFfo[],
			// 用于尚未加载的数据
			user: null as UserInfo | null,
	    }
	}
});

(1) 引入访问state

具体操作见本文:二 - 5

const store = useStore();
// 直接操作state
store.count++;

(2) 重置state

store.$reset()

(3) 同时修改多个state属性

store.$patch({
  count: store.count + 1,
  age: 120,
  isAdmin: false,
})

(4) 订阅(监听)state

import { MutationType } from 'pinia'

const store = useStore();
store.$subscribe((mutation: MutationType, state) => {
  mutation.type // 'direct' | 'patch object' | 'patch function'
  // 和 store.$id 一样
  mutation.storeId // 'storeId'
  // 只有 mutation.type === 'patch object'的情况下才可用
  mutation.payload // 传递给 cartStore.$patch() 的补丁对象。
  
  // 每当状态发生变化时,将整个 state 持久化到本地存储。
  localStorage.setItem('cart', JSON.stringify(state))
})

(5) 整个项目的pinia监听

// main.ts 具体见本文 二 - 2
const pinpa = createPinia();
watch(
  pinia.state,
  (state) => {
    // 每当状态发生变化时,将整个 state 持久化到本地存储。
    localStorage.setItem('piniaState', JSON.stringify(state))
  },
  { deep: true }
)

2. Getter

Getter 完全等同于 store 的 state 的计算值。可以通过 defineStore() 中的 getters属性来定义它们。推荐使用箭头函数,并且它将接收 state 作为第一个参数

可以通过 this 访问到整个 store 实例,但(在 TypeScript 中)必须定义返回类型。

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 2,
  }),
  getters: {
    doubleCount: (state) => state.count * 2,
  },
})

// 在组件中使用
import { useCounterStore } from './counterStore'

const store = useCounterStore()
store.doubleCount; // 注意这里使用的不是方法不需要加`()`;

3. Action

Action 相当于组件中的 method,可以通过 defineStore() 中的 actions 属性来定义

action 也可通过 this 访问整个 store 实例,并支持完整的类型标注(以及自动补全)。与Getter不同的是action 可以是异步的,可以在它们里面 await 调用任何 API,以及其他 action

import { mande } from 'mande'

const api = mande('/api/users')

export const useUsers = defineStore('users', {
  state: () => ({
    userData: null,
    // ...
  }),

  actions: {
    async registerUser(login, password) {
      try {
        this.userData = await api.post({ login, password })
        showTooltip(`Welcome back ${this.userData.name}!`)
      } catch (error) {
        showTooltip(error)
        // 让表单组件显示错误
        return error
      }
    },
  },
})

// 组件中调用
const store = useUsers()
// 将 action 作为 store 的方法进行调用
store.registerUser("login", "password");

(1) 订阅(监听)action

const unsubscribe = store.$onAction(
  ({
    name, // action 名称
    store, // store 实例,类似 `someStore`
    args, // 传递给 action 的参数数组
    after, // 在 action 返回或解决后的钩子
    onError, // action 抛出或拒绝的钩子
  }) => {
    // 为这个特定的 action 调用提供一个共享变量
    const startTime = Date.now()
    // 这将在执行 "store "的 action 之前触发。
    console.log(`Start "${name}" with params [${args.join(', ')}].`)

    // 这将在 action 成功并完全运行后触发。
    // 它等待着任何返回的 promise
    after((result) => {
      console.log(
        `Finished "${name}" after ${
          Date.now() - startTime
        }ms.\nResult: ${result}.`
      )
    })

    // 如果 action 抛出或返回一个拒绝的 promise,这将触发
    onError((error) => {
      console.warn(
        `Failed "${name}" after ${Date.now() - startTime}ms.\nError: ${error}.`
      )
    })
  }
)

// 手动删除监听器
unsubscribe()

总结

总的来说,Pinia 是一个现代化、简单、灵活且功能强大的状态管理库,适用于 Vue 3 项目,为我们提供了更好的状态管理解决方案。通过使用 Pinia,可以更轻松地管理应用程序的状态,提高开发效率并改善代码质量。

Vue Pinia 是一个基于 Vue 3 的状态管理库,可以让你更方便地管理应用程序的状态。下面是一个简单的例子,展示如何使用 Vue Pinia: 1. 安装 Vue Pinia ```bash npm install @pinia/vue3 ``` 2. 创建一个 store ```javascript import { defineStore } from '@pinia/vue3' export const useCounterStore = defineStore({ id: 'counter', state: () => ({ count: 0 }), actions: { increment() { this.count++ } } }) ``` 上面的代码创建了一个名为 `useCounterStore` 的 store,用于管理一个名为 `count` 的状态,并且提供了一个名为 `increment` 的 action,用于增加 `count` 的值。 3. 在组件中使用 store ```vue <template> <div> <p>Count: {{ count }}</p> <button @click="increment">Increment</button> </div> </template> <script> import { useCounterStore } from './store' export default { setup() { const counterStore = useCounterStore() return { count: counterStore.count, increment: counterStore.increment } } } </script> ``` 在组件中使用 `useCounterStore`,并且将 `count` 和 `increment` 绑定到组件的模板中。 4. 在应用程序中注册 store ```javascript import { createApp } from 'vue' import App from './App.vue' import { createPinia } from '@pinia/vue3' import { useCounterStore } from './store' const app = createApp(App) const pinia = createPinia() pinia.useStore(useCounterStore) app.use(pinia) app.mount('#app') ``` 在应用程序中注册 `useCounterStore`,并将其添加到 `pinia` 实例中。 以上就是使用 Vue Pinia 的一些基本步骤。通过使用 Vue Pinia,你可以轻松地管理应用程序的状态,提高开发效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小前端--可笑可笑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值