pinia

pinia

一、Vuex 与 Pinia 核心思想与用法

Flux 架构

Flux 是 Facebook 在构建大型 Web 应用程序时为了解决数据一致性问题而设计出的一种架构,它是一种描述状态管理的设计模式。绝大多数前端领域的状态管理工具都遵循这种架构,或者以它为参考原型。

Flux 架构主要有四个组成部分:

  • 📦 store:状态数据的存储管理中心,可以有多个,可以接受 action 做出响应。
  • 🖼 view:视图,根据 store 中的数据渲染生成页面,与 store 之间存在发布订阅关系。
  • 🛠 action:一种描述动作行为的数据对象,通常会包含动作类型 type 和需要传递的参数 payload 等属性。
  • 📮 dispatcher:调度器,接收 action 并分发至 store。

整个数据流动关系为:

1、view 视图中的交互行为会创建 action,交由 dispatcher 调度器。

2、dispatcher 接收到 action 后会分发至对应的 store。

3、store 接收到 action 后做出响应动作,并触发 change 事件,通知与其关联的 view 重新渲染内容。

这就是 Flux 架构最核心的特点:单向数据流。

与传统的 MVC 架构相比,单向数据流也带来了一个好处:可预测性。

所有对于状态的修改都需要经过 dispatcher 派发的 action 来触发的,每一个 action 都是一个单独的数据对象实体,可序列化,操作记录可追踪,更易于调试。

Vuex 与 Pinia 大体上沿用 Flux 的思想,并针对 Vue 框架单独进行了一些设计上的优化。

Vuex

  • 📦 state:整个应用的状态管理单例,等效于 Vue 组件中的 data,对应了 Flux 架构中的 store。
  • 🧮 getter:可以由 state 中的数据派生而成,等效于 Vue 组件中的计算属性。它会自动收集依赖,以实现计算属性的缓存。
  • 🛠 mutation:类似于事件,包含一个类型名和对应的回调函数,在回调函数中可以对 state 中的数据进行同步修改。
    • Vuex 不允许直接调用该函数,而是需要通过 store.commit 方法提交一个操作,并将参数传入回调函数。
    • commit 的参数也可以是一个数据对象,正如 Flux 架构中的 action 对象一样,它包含了类型名 type 和负载 payload
    • 这里要求 mutation 中回调函数的操作一定是同步的,这是因为同步的、可序列化的操作步骤能保证生成唯一的日志记录,才能使得 devtools 能够实现对状态的追踪,实现 time-travel。
  • 🔨 action:action 内部的操作不受限制,可以进行任意的异步操作。我们需要通过 dispatch 方法来触发 action 操作,同样的,参数包含了类型名 type 和负载 payload
    • action 的操作本质上已经脱离了 Vuex 本身,假如将它剥离出来,仅仅在用户(开发者)代码中调用 commit 来提交 mutation 也能达到一样的效果。
  • 📁 module:store 的分割,每个 module 都具有独立的 state、getter、mutation 和 action。
    • 可以使用 module.registerModule 动态注册模块。
    • 支持模块相互嵌套,可以通过设置命名空间来进行数据和操作隔离。

Pinia

保留:

  • 📦 state:store 的核心,与 Vue 中的 data 一致,可以直接对其中的数据进行读写。
  • 🧮 getters:与 Vue 中的计算属性相同,支持缓存。
  • 🔨 actions:操作不受限制,可以创建异步任务,可以直接被调用,不再需要 commit、dispatch 等方法。

舍弃:

  • 🛠 mutation:Pinia 并非完全抛弃了 mutation,而是将对 state 中单个数据进行修改的操作封装为一个 mutation,但不对外开放接口。可以在 devtools 中观察到 mutation。
  • 📁 module:Pinia 通过在创建 store 时指定 name 来区分不同的 store,不再需要 module。

二、使用Pinia

1.安装pinia

npm i pinia -S //安装pinia依赖

2.main.js组册

//main.js
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import { createPinia } from 'pinia'

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

3.创建store

//countStore.js
import { defineStore } from 'pinia'
const useCountStore = defineStore('countStore',{
    state(){
        return {
            count:0
        }
    }
} )
export default useCountStore; //导出

4.新建组件使用state

//components/Count.vue
<script setup>
import useCountStore from '../store/countStore'
const countStore = useCountStore();
console.log(countStore)
</script>
<template>
  <div>
    {{countStore.count}}
  </div>
</template>
<style lang="css">
div{
    width: 100px;
    height: 30px;
    border:1px solid black;
    border-radius: 5px;
}
</style>
//App.vue
<script setup>
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://vuejs.org/api/sfc-script-setup.html#script-setup
import Count from './components/Count.vue'
</script>

<template>
  <div>
    <Count/>
  </div>
</template>

<style scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
  filter: drop-shadow(0 0 2em #42b883aa);
}
</style>

countStore

我们可以直接使用就可以了,根据上面控制台输出可以看清楚countStore

到现在已经实现了创建store及使用

5.更新store

1.我们添加一个action方法

//countStore.js
import { defineStore } from 'pinia'

const useCountStore = defineStore('countStore',{
    //定义state
    state(){
        return {
            count:0
        }
    },
    //定义action方法
    actions:{
        add(){
            this.count++
        }
    }
} )

export default useCountStore;

2.解构方法和state

//Count.vue
<script setup>
import { storeToRefs } from 'pinia'
import useCountStore from '../store/countStore'
const {count,add} = storeToRefs(useCountStore());
</script>
<template>
  <div>
    {{count}}
  </div>
  <button @click="add()">Add</button>
</template>
<style lang="css">
div{
    width: 100px;
    height: 30px;
    border:1px solid black;
    border-radius: 5px;
    text-align: center;
}
button{
    position: relative;
    bottom: -30px;
}
</style> 

如果我们不使用 storeToRefs 来转发,那么页面将不会有任何响应

但是我们包裹了useCountStore()并且解构了,发现控制台输出错误error

经过修改发现,actions方法不可以通过解构来使用,只能通过另一种方法

参考文档:

[Pinia中文文档]: “https://pinia.web3doc.top/
[Vite中文文档]: “https://vitejs.cn/

Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2022-2023 alan_mf
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信