vue3状态管理,pinia的使用

状态管理

我们知道组件与组件之间可以传递信息,那么我们就可以将一个信息作为组件的独立状态(例如,单个组件的颜色)或者共有状态(例如,多个组件是否显示)在组件之传递,这样的话我们希望这个信息在所有组件中共享,这样就可以监控所有组件的状态,但是一般的信息传递方式想要在所有组件传递一个信息会形成一个复杂的关系网,不利于管理且中间组件若产生异常,这个关系网就会断裂,整个网页的组件就会变的无法监控,

所以我们需要一个工具来管理所有组件的状态,他需要以下几点功能

1.能够注册一个全局状态(store),形成一个中间件,让所有组件都能访问到,

2.当这个全局状态被某一个组件影响改变时,它能够让其他组件更新这个状态,

3.将信息独立出来,不因为一个组件错误,产生全局错误

vuex和pinia

vuex和pinia都是vue的状态管理工具,它们的作用相同,用法几乎没有区别,但是pinia的结构更加简洁,同时对Ts的兼容性更强。

vuex和pinia的核心

|----------------------------------|------------------------|
| vuex | pinia |
| state --- 状态信息 | state --- 状态信息 |
| getter --- 选择性的读取信息 | getter --- 选择性的读取信息 |
| mutation --- 可以执行同步操作 | action --- 可以执行同步和异步操作 |
| action --- 可以执行异步操作 返回一个mutation | action --- 可以执行同步和异步操作 |

vuex和pinia的关系

Pinia 起源于一次探索 Vuex 下一个迭代的实验,因此结合了 Vuex 5 核心团队讨论中的许多想法。最后,我们意识到 Pinia 已经实现了我们在 Vuex 5 中想要的大部分功能,所以决定将其作为新的推荐方案来代替 Vuex。

这两个工具相似度很高,作用也一致,当你熟练掌握其中一个时,另一个也能够轻松使用,这里我们还是使用pinia作为项目的状态管理器

pinia的基本使用

手动引入pinia

新建一个vue项目

复制代码
npm create vue@latest

输入完项目名称后一路回车即可,对于是否引入pinia的选项我们暂时不选则,

这里我们在src的目录下新建一个文件夹store,并在store下新建一个index.js,然后删除components文件夹的原内容,并新建两个vue文件

安装pinia包

复制代码
npm install pinia

安装完成后可以在package中看到,然后我们开始导入pinia

main.js:

javascript 复制代码
import './assets/main.css'

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

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

导入完成后我们在index.js中配置pinia

index.js:

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

export const useStore = defineStore('counter', {
    state: () => {
        return {
            // 定义状态
            counter: 0
        }
    },
    // 定义计算属性
    getters: {
        // 定义计算属性
        getCounter: (state) => {
            return state.counter>=5?state.counter:"数据不足"
        }
    },
    // 定义操作
    actions: {
        // 定义操作
        addCounter() {
            this.counter++
        }
    }
    // 定义其他选项
    // ...
})

**注意 :**第一个参数counter是返回store的一个标识,在一个项目中,我们可以新建多个store来表示多个状态,每个状态都有一个标识;第二个参数是一个对象,里面包含了state定义状态可以返回多个值(任意类型)表示状态,getter定义了一个属性运算的方法,可以用来过滤数据,只拿需要的数据(外部使用这个方法时不带括号),action定义了一个操作(可以 是异步操作,外部调用是要带括号);

然后我们再对App.vue,myComA.vue,myComB.vue引入store中间件

App.vue,

html 复制代码
<script setup>
import myComA from './components/myComA.vue'
import myComB from './components/myComB.vue'
import { useStore } from './store/index.js'
const store = useStore()

</script>

<template>
    <p>{{ store.getCounter }}</p>
    <button @click="store.addCounter()">counter = {{ store.counter }}</button>

    <myComA/>
    <myComB/>
</template>

myComA.vue,

html 复制代码
<script setup>//组合式API
import { useStore } from '../store/index'
const store = useStore()

</script>

<template>
    <div>myComA</div>
    <p>{{ store.counter }}</p>
</template>

myComB.vue

html 复制代码
<script setup>//组合式API
import { useStore } from '../store/index'
const store = useStore()

</script>

<template>
    <div>myComB</div>
    <p>{{ store.counter }}</p>
</template>

这里要注意import引入index文件的路径有所不同

完整这些后我们启动项目

html 复制代码
npm run dev

点击一次按钮,store的counter值就加一,当这个值大于等于5时,会在App.vue中显示出来,否则显示数据不足,App.vue,myComA.vue,myComB.vue 3个组件中均有显示,说明3个组件都访问到了数据,它们绑定了一个共同的信息,即便我们移除了myComB.vue其他组件也没有受到影响

这样我们就为每个组件都设置了一个状态,

系统引入pinia

掌握了手动引入pinia后,我们可以再新建一个项目查看以下系统的pinia

html 复制代码
npm create vue@latest

我们可以看到它是有一个stores文件夹的,同时再main.js,counter.js,package.json中也是有对应的配置的

我们可以观察到,它的配置方式和我们手动配置的方式有所不同,

其实这个pinia的配置类似于setup函数的结构,有选择式风格和组合式风格,这里采用的是组合式风格,2者的效果是完全一致的,可以自行对比两种方法

我们可以引入之前项目中App.vue,myComA.vue,myComB.vue 3个组件(注意这里的方法和文件名称有所改变)再启动项目查看

html 复制代码
app.vue:
<script setup>
import myComA from './components/myComA.vue'
import myComB from './components/myComB.vue'
import { useCounterStore } from './stores/counter.js'
const store =useCounterStore()

</script>

<template>
    <p>{{ store.doubleCount }}</p>
    <button @click="store.increment()">counter = {{ store.count }}</button>

    <myComA/>
    <myComB/>
</template>

myComA.vue:
<script setup>//组合式API
import { useCounterStore } from '../stores/counter.js'
const store = useCounterStore()

</script>

<template>
    <div>myComA</div>
    <p>{{ store.count }}</p>
</template>


myComB.vue:
<script setup>//组合式API
import { useCounterStore } from '../stores/counter.js'
const store = useCounterStore()

</script>

<template>
    <div>myComB</div>
    <p>{{ store.count }}</p>
</template>
html 复制代码
npm run dev

可以看到实现了状态共享,在实际应用中我们使用系统引入pinia后,可以自己手动的将pinia的相关文件调整成我们需要的结构

扩展:pinia数据持久化

登录状态的数据问题

pinia的状态共享功能最常见的使用就是登录状态的共享,它可以保存当前页面的一个登录状态,这样当你在登录页面登录成功后,其他页面可以共享这个登录状态,在一个页面退出登录后,其他页面也能够共享,这样网页就能区分用户和游客了。

但是,pinia是基于内存实现的,当你刷新页面后,pinia保存的可共享数据就会刷新,这样我们就需要重新登录,我们希望用户登录后登录状态应该由网络请求返回的token(一段有时间限制会过期的数据)保存,所以我们需要实现pinia的数据持久化,让页面刷新后仍可以保留登录状态,

实现数据持久化

想在浏览器内存下一串数据不会因为刷新而清空,我们可以想到localStorage就有这个功能,

pinia提供了一个插件,基于localStorage实现了数据的缓存,这样页面刷新后,pinia会先从localStorage中读取数据(一般是token)验证用户的登录状态,这样就不用反复登录了

pinia-plugin-persistedstate

安装插件:快速开始 | pinia-plugin-persistedstate (prazdevs.github.io)

复制代码
npm i pinia-plugin-persistedstate

安装完成后可以在package.json中查看

注册插件:

在main.js中注册引入

javascript 复制代码
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import {piniaPluginPersistedstate} from 'pinia-plugin-persistedstate'

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

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

在store下创建pinia对象的文件内启用插件

javascript 复制代码
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'

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

  return { count, doubleCount, increment }
  },
  {
    persist: true,//开启路由缓存
  },
)

App.vue

html 复制代码
<script setup>
import  {useCounterStore} from '@/stores/counter'

const {count,increment} = useCounterStore();
increment();//action方法,使用pinia的数据
console.log(count);
</script>
<template></template>
<style scoped></style>

这个counter存储的数据就会被保留在本地了

这样每次打开执行这个自增的 方法时会先从原来保存的数据执行,而不会因为刷新内存丢失掉数据,从0开始执行

总结

pinia是一个状态管理工具,它可以保存一个状态(数据),和一些方法,提供给给全局的组件共享。简单来说,pinia可以设置全局的响应量和方法,所有组件都可以访问到这些响应量和方法,并产生对应的变化

相关推荐
翻滚吧键盘5 分钟前
js代码09
开发语言·javascript·ecmascript
万少35 分钟前
第五款 HarmonyOS 上架作品 奇趣故事匣 来了
前端·harmonyos·客户端
OpenGL41 分钟前
Android targetSdkVersion升级至35(Android15)相关问题
前端
rzl021 小时前
java web5(黑马)
java·开发语言·前端
Amy.Wang1 小时前
前端如何实现电子签名
前端·javascript·html5
海天胜景1 小时前
vue3 el-table 行筛选 设置为单选
javascript·vue.js·elementui
今天又在摸鱼1 小时前
Vue3-组件化-Vue核心思想之一
前端·javascript·vue.js
蓝婷儿1 小时前
每天一个前端小知识 Day 21 - 浏览器兼容性与 Polyfill 策略
前端
百锦再1 小时前
Vue中对象赋值问题:对象引用被保留,仅部分属性被覆盖
前端·javascript·vue.js·vue·web·reactive·ref
jingling5551 小时前
面试版-前端开发核心知识
开发语言·前端·javascript·vue.js·面试·前端框架