温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Vue3状态管理之Pinia怎么使用

发布时间:2022-04-22 15:13:05 来源:亿速云 阅读:349 作者:iii 栏目:开发技术

这篇文章主要介绍“Vue3状态管理之Pinia怎么使用”,在日常操作中,相信很多人在Vue3状态管理之Pinia怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Vue3状态管理之Pinia怎么使用”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

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

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

    基于 Vite 的极速构建工具链

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

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

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

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

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

    一、Pinia 简介与基础

    1.1 Pinia 简介

    • 官方地址:https://pinia.vuejs.org/

    • Pinia 是 Vuex4 的升级版,也就是 Vuex5

    • Pinia 极大的简化了Vuex的使用,是 Vue3的新的状态管理工具

    • Pinia 对 ts的支持更好,性能更优, 体积更小,无 mutations,可用于 Vue2 和 Vue3

    • Pinia支持Vue Devtools、 模块热更新和服务端渲染

    1.2 Pinia 基础

    &emsp;&emsp;Vuex 与 Pinia 对比

    • Vuex 中核心部分: State、Getters、Mutations(同步) 和 Actions(异步)

    • Pinia 中核心部分: State、Getters 和 Actions(同步异步均支持)

    &emsp;&emsp;Pinia 各部分作用

    • State: 类似于组件中data,用于存储全局状态

    • Getters: 类似于组件中的computed,根据已有的State封装派生数据,也具有缓存的特性

    • Actions: 类似于组件中的methods,用于封装业务逻辑,同步异步均可以

    &emsp;&emsp;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:\Users\FORGET\Desktop\vue-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:\Users\FORGET\Desktop\vue-pinia-demo\pinia-demo...
    
    Done. Now run:
    
      cd pinia-demo
      npm install
      npm run dev
    PS C:\Users\FORGET\Desktop\vue-pinia-demo> cd .\pinia-demo\
    PS C:\Users\FORGET\Desktop\vue-pinia-demo\pinia-demo> npm install

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

    PS C:\Users\FORGET\Desktop\vue-pinia-demo\pinia-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 同步和异步请求

    ⑤ 在组件中使用

    <template>
      <h2>{{ mainStore.info}}</h2>
    </template>
    
    <script lang="ts" setup>
    import { useMainStore } from "../store";
    const mainStore = useMainStore();
    </script>
    
    <style>
    </style>

    2.2 state 中数据的解构访问

    状态管理中

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

    组件中

    <template>
      <h2>{{ mainStore.count }}</h2>
      <h2>{{ mainStore.info }}</h2>
      <hr />
      <h2>{{ count }}</h2>
      <h2>{{ info }}</h2>
      <p>
        <button @click="alertData">修改数据</button>
      </p>
    </template>
    
    <script lang="ts" setup>
    import { toRefs } from 'vue'
    import { storeToRefs } from 'pinia'
    import { useMainStore } from "../store";
    const mainStore = useMainStore();
    // 解构数据,但是得到的数据是不具有响应式的,只是一次性的
    // 相当于仅仅只是...mainStore而已,只是做了reactive处理,并没有做toRefs
    // const { count, info } = useMainStore();
    // 解决方法:
    // 1. 通过使用toRefs函数,因为前面所说相当于是通过reactive处理,因此可以
    // const { count, info } = toRefs(mainStore);
    // 2. 通过pinia中提供的storeToRefs方法来解决,推荐使用
    const { count, info } = storeToRefs(mainStore);
    const alertData = () => {
      mainStore.count += 10
    }
    </script>
    
    <style>
    </style>

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

    一般的修改

    const alertData = () => {
      // 方式一:最简单的方法,如下
      // 解构后更改方式
      // count.value += 10
      // 结构前更改方式
      // mainStore.count += 10
      // 方式二:若要同时修改多个数据,建议使用$patch来实现批量更新,在内部做了优化
      // mainStore.$patch({
      //   count: mainStore.count + 1,
      //   info: "hello"
      // })
      // 方式三:更好的批量更新方法,通过$patch传递一个函数来实现,这里的state就是useMainStore容器中的state
      mainStore.$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
      // 方式二:若要同时修改多个数据,建议使用$patch来实现批量更新,在内部做了优化
      // mainStore.$patch({
      //   count: mainStore.count + 1,
      //   info: "hello"
      // })
      // 方式三:更好的批量更新方法,通过$patch传递一个函数来实现,这里的state就是useMainStore容器中的state
      // 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
            }
        },

    使用

    <h2>{{ mainStore.count10 }}</h2>

    三、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.$subscribe((_, state) => {
      localStorage.setItem('login-store', JSON.stringify({ ...state }));
    });
    // 2. 获取保存的数据,先判断有无,无则用先前的
    const old = localStorage.getItem('login-store');
    if (old) {
      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'],
          },
        ],
      },

    到此,关于“Vue3状态管理之Pinia怎么使用”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI