vue3新一代状态管理器 — pinia的学习与使用

一、vuex与pinia

在这里插入图片描述

Pinia 最初是为了探索 Vuex 的下一次迭代会是什么样子,结合了 Vuex 5 核心团队讨论中的许多想法。最终,我们意识到 Pinia 已经实现了我们在 Vuex 5 中想要的大部分内容,并决定实现它 取而代之的是新的建议。

可以理解为pinia就是下一代的vuex5,但是vuex团队为了尊重pinia作者对于vuex的开发贡献,就直接使用pinia命名了。
pinia中文文档

特性

  1. 完全支持typescript
  2. 足够轻量,压缩后体积只有1.6kb
  3. 模块化的设计,在打包时引入的每一个store都可以自动拆分
  4. 没有模块嵌套,只有store概念,store之间可以自由使用,实现更好的代码分隔
  5. actions支持同步和异步,去除了mutation
  6. 支持VueDevtools

二、使用pinia

2.1 安装pinia

用你最喜欢的包管理器安装 pinia:

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

2.2 项目引入

使用createPinia将pinia引入项目中。

main.ts:

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

createApp(App).use(createPinia()).mount('#app')

2.3 创建store

src目录下创建store文件夹,用于存放store对应的js/ts文件,未来方便管理,我们可以在一个js/ts文件中只定义一个store,例如我们定义一个user.ts文件,用于存储用户相关的信息和操作:
在这里插入图片描述
pinia使用defineStore创建store,包含了id、state、getters和actions:

// @ts-check
import {
    
     defineStore } from 'pinia'

/**
 * Simulate a login
 */
function apiLogin(a: string, p: string) {
    
    
  if (a === 'ed' && p === 'ed') return Promise.resolve({
    
     isAdmin: true })
  if (p === 'ed') return Promise.resolve({
    
     isAdmin: false })
  return Promise.reject(new Error('invalid credentials'))
}

export const useUserStore = defineStore({
    
    
  id: 'user',
  state: () => ({
    
    
    name: 'Eduardo',
    isAdmin: true,
  }),
  
  getters:{
    
    
	userName: (state) => `Get userName from getter ${
      
      state.name}`
  },
  
  actions: {
    
    
  /**
  * 退出logout
  */
    logout() {
    
    
      this.$patch({
    
    
        name: '',
        isAdmin: false,
      })
  /**
   * 登录 login
   */
    async login(user: string, password: string) {
    
    
      const userData = await apiLogin(user, password)
      this.$patch({
    
    
        name: user,
        ...userData,
      })
    },
  },
})

相比较于vuex,pinia去除了mutation,同步和异步操作都通过actions,并且没有了module的概念,defineStore会创建一个新的store。

2.4 使用store

在组件中引入定义好的store并调用:

<script setup lang="ts">
import {
      
       useUserStore } from "./store/user"

const userStore = useUserStore()

//访问state
console.log(userStore.name)
//访问getter
console.log(userStore.userName)
</script>

然后就可以通过user来访问store中的state,并且还可以调用getter和action。

getter

Getter 完全等同于 Store 状态的计算值。 它们可以用 defineStore() 中的 getters 属性定义。 他们接收“状态”作为第一个参数以鼓励箭头函数的使用,可以直接在 store 实例上访问 getter。
我们也可以在定义常规函数时通过 this 访问到整个 store 的实例。

action

Actions 相当于组件中的 methods。 它们可以使用 defineStore() 中的 actions 属性定义,并且它们非常适合定义业务逻辑,也可以直接在store实例上调用action。
在actions中也可以在定义常规函数时通过 this 访问到整个 store 的实例。

export const useStore = defineStore('main', {
    
    
  state: () => ({
    
    
    counter: 0,
  }),
  actions: {
    
    
    increment() {
    
    
      this.counter++
    },
    randomizeCounter() {
    
    
      this.counter = Math.round(100 * Math.random())
    },
  },
})

2.5 修改state

1、直接修改

虽然可以通过pinia实例直接修改,但是出于代码结构来说,全局的状态管理还是不要直接在各个组件处随意修改状态,应放于 action 中统一方法修改(piain没有mutation)并不推荐!

store.count ++;

2、使用$patch

使用$patch改变数据 $patch 可以同时修改多个值。

store.$patch((state) => {
    
    
        state.name= 'newName'
        state.age ++
      })

3、使用actions

推荐。

actions:{
    
    
    async login(user: string, password: string) {
    
    
      //模拟异步登录
      const userData = await apiLogin(user, password)
      //更新state中数据
      this.$patch({
    
    
        name: user,
        ...userData,
      })
    }
}

2.6 storeToRefs

为了直接获取store中的属性,我们可能会利用解构来直接获取:

import {
    
     useUserStore } from "./store/user"

const {
    
     name }= useUserStore()

但是,值得注意的是,如果直接解构store实例来获取state中的值,那么获取的值就失去了响应式,正确的做法是使用storeToRefs:

import {
    
     storeToRefs } from 'pinia'
import {
    
     useUserStore } from "./store/user"

const {
    
     name }= storeToRefs(useUserStore())

猜你喜欢

转载自blog.csdn.net/ZHANGYANG_1109/article/details/128036448