Vue3 状态管理之 Pinia 的使用

31 篇文章 0 订阅

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vd57lnAa-1647002874040)(https://pinia.vuejs.org/logo.svg#pic_center)]

Vue3 新的发展方向(来源于尤大知乎)

  • Vue 3 将在 2022 年 2 月 7 日 成为新的默认版本

  • 基于 Vite 的极速构建工具链

  • <script setup> 带来的开发体验更丝滑的组合式 API 语法

  • Volar 提供的单文件组件 TypeScript IDE 支持

  • vue-tsc 提供的针对单文件组件的命令行类型检查和生成

  • Pinia 提供的更简洁的状态管理

  • 新的开发者工具扩展,同时支持 Vue 2/Vue 3,并且提供一个插件系统来允许社区库自行扩展开发者工具面板。

一、Pinia 简介与基础

1.1 Pinia 简介

  • 官方地址:[这里是代码003]
  • PiniaVuex4 的升级版,也就是 Vuex5
  • Pinia 极大的简化了Vuex的使用,是 Vue3的新的状态管理工具
  • Piniats的支持更好,性能更优, 体积更小,无 mutations,可用于 Vue2Vue3
  • Pinia支持Vue Devtools、 模块热更新和服务端渲染

1.2 Pinia 基础

Vuex 与 Pinia 对比

  • Vuex 中核心部分: StateGettersMutations(同步) 和 Actions(异步)
  • Pinia 中核心部分: StateGettersActions(同步异步均支持)

Pinia 各部分作用

  • State 类似于组件中data,用于存储全局状态
  • Getters 类似于组件中的computed,根据已有的State封装派生数据,也具有缓存的特性
  • Actions 类似于组件中的methods,用于封装业务逻辑,同步异步均可以

Pinia 官方示例JS版本

import { defineStore } from 'pinia'

export const todos = defineStore('todos', {
  state: () => ({
    /** @type {{ text: string, id: number, isFinished: boolean }[]} */
    todos: [],
    /** @type {'all' | 'finished' | 'unfinished'} */
    filter: 'all',
    // type will be automatically inferred to number
    nextId: 0,
  }),
  getters: {
    finishedTodos(state) {
      // autocompletion! ?
      return state.todos.filter((todo) => todo.isFinished)
    },
    unfinishedTodos(state) {
      return state.todos.filter((todo) => !todo.isFinished)
    },
    /**
     * @returns {{ text: string, id: number, isFinished: boolean }[]}
     */
    filteredTodos(state) {
      if (this.filter === 'finished') {
        // call other getters with autocompletion ?
        return this.finishedTodos
      } else if (this.filter === 'unfinished') {
        return this.unfinishedTodos
      }
      return this.todos
    },
  },
  actions: {
    // any amount of arguments, return a promise or not
    addTodo(text) {
      // you can directly mutate the stat 00e
      this.todos.push({ text, id: this.nextId++, isFinished: false })
    },
  },
})

二、Pinia 在Vue3-Vite中的使用

2.1 基础使用流程

  • ① 创建一个vue vite项目

    PS C:UsersFORGETDesktopvue-pinia-demo> npm init vite@latest
    Need to install the following packages:
    create-vite@latest
    Ok to proceed? (y) y
    √ Project name: … pinia-demo
    √ Select a framework: ? vue
    √ Select a variant: ? vue-ts

    Scaffolding project in C:UsersFORGETDesktopvue-pinia-demopinia-demo…

    Done. Now run:

    cd pinia-demo
    npm install
    npm run dev
    PS C:UsersFORGETDesktopvue-pinia-demo> cd .pinia-demo
    PS C:UsersFORGETDesktopvue-pinia-demopinia-demo> npm install

  • ② 安装 pinia-S是为了将其保存至package.json中,便于Git管理给其他人的使用

    PS C:UsersFORGETDesktopvue-pinia-demopinia-demo> npm install pinia -S

    package.json文件中

    “dependencies”: {
    “pinia”: “^2.0.9”,
    “vue”: “^3.2.25”
    },

  • ③ 创建 pinia 实例并挂载到 vue

    // main.ts 文件
    import { createApp } from ‘vue’
    import App from ‘./App.vue’
    import {createPinia} from ‘pinia’
    // 创建 Pinia 实例
    const pinia = createPinia()
    // 创建 Vue 实例
    const app = createApp(App)
    // 挂载到 Vue 根实例
    app.use(pinia)
    app.mount(’#app’)

  • ④ 在src文件下创建一个store文件夹,并添加index.ts

    // store/index.ts
    import { defineStore } from ‘pinia’
    // 1. 定义容器、导出容器
    // 参数1:容器的ID,必须是唯一的,后面Pinia会把所有的容器挂载到根容器
    // 参数2:一些选项对象,也就是state、getter和action
    // 返回值:一个函数,调用即可得到容器实例

    export const useMainStore = defineStore(‘main’,{
    // 类似于Vue2组件中的data,用于存储全局状态数据,但有两个要求
    // 1. 必须是函数,目的是为了在服务端渲染的时候避免交叉请求导致的数据状态污染
    // 2. 必须是箭头函数,这样是为了更好的 TS 类型推导
    state:()=>{
    return {
    info:“pinia 可以使用”
    }
    },
    getters:{},
    actions:{}
    })

    // 2. 使用容器中的 state
    // 3. 通过 getter 修改 state
    // 4. 使用容器中的 action 同步和异步请求

  • ⑤ 在组件中使用

    {{ mainStore.info}}

2.2 state 中数据的解构访问

  • 状态管理中

    // store/index.ts
    state:()=>{
    return {
    info:“pinia 可以使用”,
    count:10
    }
    },

  • 组件中

    {{ mainStore.count }}

    {{ mainStore.info }}


    {{ count }}

    {{ info }}

2.3 state 中数据的修改方式(actions和组件中)

  • 一般的修改

    const alertData = () => {
    // 方式一:最简单的方法,如下
    // 解构后更改方式
    // count.value += 10
    // 结构前更改方式
    // mainStore.count += 10
    // 方式二:若要同时修改多个数据,建议使用 p a t c h 来 实 现 批 量 更 新 , 在 内 部 做 了 优 化 / / m a i n S t o r e . patch来实现批量更新,在内部做了优化 // mainStore. patch//mainStore.patch({
    // count: mainStore.count + 1,
    // info: “hello”
    // })
    // 方式三:更好的批量更新方法,通过 p a t c h 传 递 一 个 函 数 来 实 现 , 这 里 的 s t a t e 就 是 u s e M a i n S t o r e 容 器 中 的 s t a t e m a i n S t o r e . patch传递一个函数来实现,这里的state就是useMainStore容器中的state mainStore. patchstateuseMainStorestatemainStore.patch(state => {
    state.count += 10
    state.info = “pinia批量更新”
    })
    }

  • 通过actions修改

    // store/index.ts
    // 类似于vue2组件的methods,用于封装业务逻辑,修改state
    // // 注意:不能使用箭头函数来定义actions,因为箭头函数绑定外部的this
    actions:{
    changeState (){
    this.count += 10
    this.info = “actions修改数据”
    },
    changeStates (num:number){
    this.count += num + 2
    this.info = “actions修改数据”
    }
    }

    const alertData = () => {
    // 方式一:最简单的方法,如下
    // 解构后更改方式
    // count.value += 10
    // 结构前更改方式
    // mainStore.count += 10
    // 方式二:若要同时修改多个数据,建议使用 p a t c h 来 实 现 批 量 更 新 , 在 内 部 做 了 优 化 / / m a i n S t o r e . patch来实现批量更新,在内部做了优化 // mainStore. patch//mainStore.patch({
    // count: mainStore.count + 1,
    // info: “hello”
    // })
    // 方式三:更好的批量更新方法,通过 p a t c h 传 递 一 个 函 数 来 实 现 , 这 里 的 s t a t e 就 是 u s e M a i n S t o r e 容 器 中 的 s t a t e / / m a i n S t o r e . patch传递一个函数来实现,这里的state就是useMainStore容器中的state // mainStore. patchstateuseMainStorestate//mainStore.patch(state => {
    // state.count += 10
    // state.info = “pinia批量更新”
    // })
    // 方式四:通过 actions 来修改数据
    mainStore.changeState()
    mainStore.changeStates(10)
    }

2.4 getters 的使用

  • 定义

    // 类似于组件的computed,用来封装计算属性,具有缓存的功能
    getters:{
    // 函数接收一个可选参数:state状态对象
    count10(state){
    return state.count += 10
    },
    count10(state){
    return this.count += 10
    },
    // 若使用this.count,则必须指明返回数据的类型
    count11():number{
    return this.count += 11
    }
    },

  • 使用

    {{ mainStore.count10 }}

三、Pinia 数据持久化

  • 保存至localStorage中

    import { defineStore } from ‘pinia’;
    const useLoginStore = defineStore({
    id: ‘login’,
    // state: () => ({
    // num: 1,
    // }),
    state: () => ({
    info: ‘pinia 可以使用’,
    }),
    getters: {},
    actions: {
    alertInfo() {
    this.info = ‘可以可以,这个秒’;
    },
    },
    });

    // 数据持久化
    // 1. 保存数据
    const instance = useLoginStore();
    instance.KaTeX parse error: Expected '}', got 'EOF' at end of input: …) { instance.state = JSON.parse(old);
    }
    export default useLoginStore;

  • 使用 插件 pinia-plugin-persist 可以辅助实现数据持久化功能

    安装插件

    pnpm install pinia-plugin-persist --save

    // main.ts文件中
    import { createPinia } from ‘pinia’;
    import { createApp } from ‘vue’;
    import App from ‘./App.vue’;
    import router from ‘./router’;
    import piniaPluginPersist from ‘pinia-plugin-persist’;
    const pinia = createPinia();
    pinia.use(piniaPluginPersist);
    const app = createApp(App);
    app.use(router);
    app.use(pinia);
    app.mount(’#app’);

    // 接着在对应的 store 里开启 persist 即可。数据默认存在 sessionStorage 里,并且会以 store 的 id 作为 key。
    import { defineStore } from ‘pinia’;
    import piniaPluginPersist from ‘pinia-plugin-persist’;
    const useLoginStore = defineStore({
    id: ‘login’,
    // state: () => ({
    // num: 1,
    // }),
    state: () => ({
    info: ‘pinia 可以使用’,
    }),
    // 开启数据缓存
    persist: {
    enabled: true,
    },
    getters: {},
    actions: {
    alertInfo() {
    this.info = ‘可以可以,这个秒’;
    },
    },
    });
    export default useLoginStore;

  • 其它设置,自定义保存名称,保存位置和需要保存的数据

    // 开启数据缓存
    persist: {
    enabled: true,
    strategies: [
    {
    // 自定义名称
    key: ‘login_store’,
    // 保存位置,默认保存在sessionStorage
    storage: localStorage,
    // 指定要持久化的数据,默认所有 state 都会进行缓存,你可以通过 paths 指定要持久化的字段,其他的则不会进行持久化。
    paths: [‘age’],
    },
    ],
    },

,

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值