vue全家桶之状态管理Pinia

一、Pinia和Vuex的对比

1.什么是Pinia呢?

Pinia(发音为/piːnjʌ/,如英语中的"peenya")是最接近piña(西班牙语中的菠萝)的词;

  • Pinia开始于大概2019年,最初是作为一个实验为Vue重新设计状态管理,让它用起来像组合式API(Composition API)。

  • 从那时到现在,最初的设计原则依然是相同的,并且目前同时兼容Vue2、Vue3,也并不要求你使用Composition API;

  • Pinia本质上依然是一个状态管理的库,用于跨组件、页面进行状态共享(这点和Vuex、Redux一样);

2.Pinia和Vuex的区别

那么我们不是已经有Vuex了吗?为什么还要用Pinia呢?

  • Pinia 最初是为了探索 Vuex 的下一次迭代会是什么样子,结合了 Vuex 5 核心团队讨论中的许多想法;
  • 最终,团队意识到Pinia已经实现了Vuex5中大部分内容,所以最终决定用Pinia来替代Vuex
  • 与 Vuex 相比,Pinia 提供了一个更简单的 API,具有更少的仪式,提供了 Composition-API 风格的 API;
  • 最重要的是,在与 TypeScript 一起使用时具有可靠的类型推断支持;

和Vuex相比,Pinia有很多的优势:

  • 比如mutations 不再存在:
    • 他们经常被认为是非常冗长;
    • 他们最初带来了 devtools 集成,但这不再是问题;
  • 更友好的TypeScript支持,Vuex之前对TS的支持很不友好;
  • 不再有modules的嵌套结构:
    • 你可以灵活使用每一个store,它们是通过扁平化的方式来相互使用的;
  • 也不再有命名空间的概念,不需要记住它们的复杂关系;

二、创建Pinia的Store

1.如何使用Pinia?

使用Pinia之前,我们需要先对其进行安装:

shell 复制代码
yarn add pinia
# or with npm
npm install pinia

创建一个pinia并且将其传递给应用程序:

javascript 复制代码
import { createPinia } from 'pinia'

const pinia = createPinia()

export default pinia
javascript 复制代码
import pinia from './store'

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

2.认识Store

什么是Store?

  • 一个 Store (如 Pinia)是一个实体,它会持续绑定到你组件树的状态和业务逻辑,也就是保存了全局的状态;
  • 它有点像始终存在,并且每个人都可以读取和写入的组件;
  • 你可以在你的应用程序中定义任意数量的Store来管理你的状态;

Store有三个核心概念:

  • stategettersactions
  • 等同于组件的data、computed、methods;
  • 一旦 store 被实例化,你就可以直接在 store 上访问 state、getters 和 actions 中定义的任何属性;

3.定义一个Store

定义一个Store:

  • 我们需要知道 Store 是使用 defineStore() 定义的,
  • 并且它需要一个唯一名称,作为第一个参数传递;
javascript 复制代码
export const useCounter = defineStore("counter", {
    state() {
        return {
            counter: 0
        }
    }
})

这个 name,也称为 id,是必要的,Pinia 使用它来将 store 连接到 devtools。

返回的函数统一使用useX作为命名方案,这是约定的规范;

4.使用定义的Store

Store在它被使用之前是不会创建的,我们可以通过调用use函数来使用Store:

html 复制代码
<template>
<div class="app">
  app.vue
  <div class="counter">
    counter: {{ counterStore.count }}
  </div>
</div>
</template>

<script setup>
import useCounter from './stores/counter'

const counterStore = useCounter()

</script>

注意Store获取到后不能被解构,那么会失去响应式:

  • 为了从 Store 中提取属性同时保持其响应式,您需要使用storeToRefs()
javascript 复制代码
const counterStore = useCounter()
// 不是响应式
const { count } = counterStore
// 响应式
const { count: count1 } = toRefs(counterStore)
// 响应式
const { count: count2 } = storeToRefs(counterStore)

三、Pinia核心概念State

1.认识和定义State

state 是 store 的核心部分,因为store是用来帮助我们管理状态的。

  • 在 Pinia 中,状态被定义为返回初始状态的函数;
javascript 复制代码
const useCounter = defineStore("counter", {
    state: () => ({
       counter: 0
    })
})

2.操作State

读取和写入 state:

  • 默认情况下,您可以通过 store 实例访问状态来直接读取和写入状态;
javascript 复制代码
const counterStore = useCounter()
counterStore.count++
counterStore.name = 'codermy'

重置 State:

  • 你可以通过调用 store 上的 $reset() 方法将状态 重置 到其初始值;
javascript 复制代码
const counterStore = useCounter()
counterStore.$reset()

改变State:

  • 除了直接用 store.counter++ 修改 store,你还可以调用 $patch 方法;
  • 它允许您使用部分"state"对象同时应用多个更改
javascript 复制代码
const counterStore = useCounter()
counterStore.$patch({
    counter: 100,
    name: 'kobe'
})

替换State:

  • 您可以通过将其 $state 属性设置为新对象来替换 Store 的整个状态:
javascript 复制代码
counterStore.$state = {
    counter: 1,
    name: 'monic'
}

四、Pinia核心概念Getters

1.认识和定义Getters

Getters相当于Store的计算属性

  • 它们可以用 defineStore() 中的 getters 属性定义;
  • getters中可以定义接受一个state作为参数的函数
javascript 复制代码
const useCounter = defineStore("counter", {
    state: () => ({
       counter: 0
    }),
    getters: {
        doubleCounter: (state) => state.count * 2
    }
})

2.访问Getters

访问当前store的Getters:

javascript 复制代码
const counterStore = useCounter()
counterStore.doubleCounter

Getters中访问自己的其他Getters:

  • 我们可以通过this来访问到当前store实例的所有其他属性;
javascript 复制代码
doublePlusOne: function(state) {
    return this.doubleCounter + 1
}

访问其他store的Getters:

javascript 复制代码
message: function(state) {
    const userStore = useUser()
    return this.fullname + ':' + userStore.nickname
}

Getters也可以返回一个函数,这样就可以接受参数:

javascript 复制代码
const useCounter = defineStore("main", {
    state: () => ({
       users: [
           {id: 111, name: 'kobe', age: 19},
           {id: 112, name: 'james', age: 15},
           {id: 113, name: 'mike', age: 29},
       ]
    }),
    getters: {
        getUserById: (state) => {
            return userId => {
                const user = state.users.find(item => item.id === userId)
                return user
            }
        }
    }
})

五、Pinia核心概念Actions

1.认识和定义Actions

Actions 相当于组件中的 methods。

  • 可以使用 defineStore() 中的 actions 属性定义,并且它们非常适合定义业务逻辑;
javascript 复制代码
actions: {
    increment() {
        this.counter++
    },   
}
javascript 复制代码
function add() {
     counterStore.increment()
} 

和getters一样,在action中可以通过this访问整个store实例的所有操作;

2.Actions执行异步操作

并且Actions中是支持异步操作的,并且我们可以编写异步函数,在函数中使用await;

javascript 复制代码
import { defineStore } from 'pinia'

const useHome = defineStore("home", {
  state: () => ({
    banners: [],
    recommends: []
  }),
  actions: {
    async fetchHomeMultidata() {
      const res = await fetch("http://xxx.xxx:8000/home/multidata")
      const data = await res.json()

      this.banners = data.data.banner.list
      this.recommends = data.data.recommend.list
      
      // return new Promise(async (resolve, reject) => {
      //   const res = await fetch("http://xxx:8000/home/multidata")
      //   const data = await res.json()

      //   this.banners = data.data.banner.list
      //   this.recommends = data.data.recommend.list

      //   resolve("bbb")
      // })
    }
  }
})

export default useHome
javascript 复制代码
import { useHome } from './stores/home'

const homeStore = useHome()
homeStore.fetchHomeMultidata().then(res => {
    console.log(res)
})
相关推荐
你挚爱的强哥3 小时前
✅✅✅【Vue.js】sd.js基于jQuery Ajax最新原生完整版for凯哥API版本
javascript·vue.js·jquery
y先森4 小时前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy4 小时前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu10830189114 小时前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
sun0077004 小时前
ubuntu dpkg 删除安装包
运维·服务器·ubuntu
IT女孩儿5 小时前
CSS查缺补漏(补充上一条)
前端·css
shuangrenlong6 小时前
slice介绍slice查看器
java·ubuntu
吃杠碰小鸡6 小时前
commitlint校验git提交信息
前端
天天进步20156 小时前
Vue+Springboot用Websocket实现协同编辑
vue.js·spring boot·websocket
虾球xz7 小时前
游戏引擎学习第20天
前端·学习·游戏引擎