美文网首页前端开发
Pinia快速入门-上手指南

Pinia快速入门-上手指南

作者: 神奇的呆子 | 来源:发表于2022-05-30 09:36 被阅读0次

    Pinia是什么

    PiniaVue 的存储库,允许您跨组件/页面共享状态。Pinia 这款产品最初是为了探索 Vuex 的下一个版本,整合了核心团队关于 Vuex 5 的许多想法。最终,我们意识到 Pinia 已经实现了我们想要在 Vuex 5 中提供的大部分内容,因此决定将其作为 新的官方推荐

    Pinia特点

    • 足够轻量,Pinia 重约 1kb,甚至会忘记它的存在!
    • 去除 MutationActions 支持同步和异步(Actions一个顶俩,写起来简洁);
    • 无需手动注册 Store,Store 仅需要时才自动注册。如果从不使用,则永远不会“注册”(省心);
    • 没有模块嵌套,只有 Store 的概念,Store 之间可以自由使用,更好的代码分割;
    • Vue2Vue3 都能支持;
    • 支持大型项目迁移期间,PiniaVuex 混合使用(贴心迁移);
    • 更完美的 typescript 的支持;
    • Vue devtools 挂钩,Vue2 和 Vue3 开发体验更好;
    • 支持插件扩展功能;
    • 支持模块热更新,无需加载页面可以修改容器,可以保持任何现有的状态;
    • 支持服务端渲染;

    VuexPinia 用哪个

    Vuex 现在处于维护模式。它仍然可以工作,但不再添加新的功能。对于新的应用项目,建议使用 PiniaPinia 已经实现了我们想要在 Vuex 5 中提供的大部分内容,因此决定将其作为 新的官方推荐(注意:旧版网站没有更新)

    如何使用 Pinia

    一、安装

    npm install pinia
    

    vue2需要另外安装

    npm i pinia @vue/composition-api --save
    

    二、定义 Store

    新建 src/stores 目录并在其下面创建 index.ts

    Pinia 的目录通常被称为 stores 而不是 store, 这是为了强调 Pinia 使用多个 store,而不是 Vuex 中的单个 store,同时也有迁移期间 PiniaVuex 混合使用的考虑。

    // src/stores/index.ts
    // 引入Store定义函数
    import { defineStore } from 'pinia'
    
    // 定义Store实例并导出,useStore可以是任何东西,比如useUser, useCart
    // 第一个参数,唯一不可重复,字符串类型,作为仓库ID 以区分仓库
    // 第二个参数,以对象形式配置仓库的state,getters,actions
    export const useStore = defineStore('main', {
      // state 推荐箭头函数,为了TS类型推断
      state: () => {
        return {
          name: '张三',
          counter: 0
        }
      },
      getters: {},
      actions: {}
    })
    

    在 main.ts 中引入并挂载到根实例。

    // src/main.ts
    import { createApp } from 'vue'
    import App from './App.vue'
    import { createPinia } from 'pinia'
    // 创建Vue应用实例
    // 实例化 Pinia
    // 以插件形式挂载Pinia实例
    createApp(App).use(createPinia()).mount('#app')
    

    vue2写法

    定义store同vue3,main.js中引入并挂在到跟实例代码如下:

    //main.js引入
    // 引入pinia
    import {createPinia,PiniaVuePlugin} from 'pinia'
    Vue.use(PiniaVuePlugin)
    const pinia = createPinia()//需要挂载在实例上
    
    new Vue({
      router,
      pinia,
      render: h => h(App)
    }).$mount('#app')
    

    vue2中如果报如下错误,


    则需要在vue.config.js中增加以下配置:


    三、State

    1、访问State

    <template>
      <div>
         <button @click="handleClick">修改状态数据</button>
         <!-- 模板内不需要加.value -->
         <p>{{store.name}}</p>
         <!-- computed获取 -->
         <p>{{name}}</p>
         <!-- 或者使用解构之后的 -->
         <p>{{counter}}</p>
      </div>
    </template>
    
    <script lang="ts" setup>
    import { useStore } from '@/stores/index.ts'
    // 使普通数据变响应式的函数  
    import { storeToRefs } from "pinia";
    
    const store = useStore()
    
    // 结合computed获取
    const name = computed(() => store.name)
    // 解构并使数据具有响应式
    const { counter } = storeToRefs(store);
    
    // 点击 + 1;
    function handleClick() {
      // ref数据这里需要加.value访问
      counter.value++;
    }
    </script>
    

    2、修改State

    1、单个参数修改 state

    store.counter++
    

    2、多个参数修改 state

    store.$patch({
      counter: store.counter + 1,
      name: 'Abalam',
    })
    

    3、全部修改 state

    store.$state = { counter: 666, name: 'Paimon' }
    或
    pinia.state.value = {}
    

    3、重置State

    将状态重置为初始值

    const store = useStore()
    store.$reset()
    

    4、vue2写法

    import { mapState } from 'pinia'
    import { useCounterStore } from '../stores/counterStore'
    
    export default {
      computed: {
        ...mapState(useCounterStore, ['counter'])
        // 或
        ...mapState(useCounterStore, {
          myOwnName: 'counter',
          double: store => store.counter * 2,
          magicValue(store) {
            return store.someGetter + this.counter + this.double
          },
        }),
      },
    }
    

    四、Getters

    getter 中的值有缓存特性,类似于computed,如果值没有改变,多次使用也只会调用一次

    1、定义Getters:

    export const useStore = defineStore('main', {
      state: () => ({
        counter: 0,
      }),
      getters: {
        doubleCount: (state) => state.counter * 2,
        // 自动推导返回类型
        doubleCount(state) {
          return state.counter * 2
        },
        // 依赖getters返回参数,则需要显性的设置返回类型
        doublePlusOne(): number {
          return this.doubleCount + 1
        },
      },
    })
    

    2、使用Getters

    <template>
      <p>Double count is {{ store.doubleCount }}</p>
    </template>
    
    <script>
    export default {
      setup() {
        const store = useStore()
        
        return { store }
      },
    }
    </script>
    

    3、vue2写法

    import { mapState } from 'pinia'
    import { useCounterStore } from '../stores/counterStore'
    
    export default {
      computed: {
        ...mapState(useCounterStore, ['doubleCount'])
        // 或
        ...mapState(useCounterStore, {
          myOwnName: 'doubleCounter',
          double: store => store.doubleCount,
        }),
      },
    }
    

    五、Actions

    Pinia 中删除了 MutationActions 支持同步和异步

    1、定义 Actions

    // 同步
    export const useStore = defineStore('main', {
      state: () => ({
        counter: 0,
        userData: null,
      }),
      actions: { 
        increment() {
          this.counter++
        },
        randomizeCounter() {
          this.counter = Math.round(100 * Math.random())
        },
      },
    })
    
    // 异步
    import { mande } from 'mande'
    const api = mande('/api/users')
    
    export const useUsers = defineStore('users', {
      state: () => ({
        userData: null,
      }),
    
      actions: {
        async registerUser(login, password) {
          this.userData = await api.post({ login, password })
        },
      },
    })
    

    2、调用 Actions

    1、可以直接调用 store 的任何方法

    <script>
    export default {
      setup() {
        const store = useStore()
        store.randomizeCounter()
      },
    }
    </script>
    

    2、action 间的相互调用,直接用 this 访问即可。

     export const useUserStore = defineStore({'user',
      actions: {
        increment() {
          this.counter++
        },
        increase() {
          // 调用另一个 action 的方法
          this.increment()
        },
      }
    })
    
    

    3、在 action 里调用其他 store 里的 action 也比较简单,引入对应的 store 后即可访问其内部的方法。

    import { useAuthStore } from './auth-store'
    
    export const useSettingsStore = defineStore('settings', {
      state: () => ({
        preferences: null,
      }),
      actions: {
        async fetchUserPreferences() {
          // 调用 auth-store store 里的 action 方法
          const auth = useAuthStore()
          if (auth.isAuthenticated) {
            this.preferences = await fetchPreferences()
          } else {
            throw new Error('User must be authenticated')
          }
        },
      },
    })
    

    3、vue2写法

    import { mapActions } from 'pinia'
    import { useCounterStore } from '../stores/counterStore'
    
    export default {
      methods: {
        ...mapActions(useCounterStore, ['increment'])
        // 或
        ...mapActions(useCounterStore, { myOwnName: 'doubleCounter' }),
      },
    }
    

    总结

    总得来说,Pinia 就是 Vuex 的官方替代版,可以更好的支持 Vue2,Vue3以及TypeScript。在 Vuex 的基础上去掉了 Mutation模块嵌套等概念,语法更简洁直接, 更符合 Vue3 的 Composition api,为 TypeScript 提供了更好的类型推导。以上是 Pinia.js 用法的一些介绍,Pinia.js 的内容还远不止这些,更多内容及使用有待大家自己探索。Pinia文档

    参考文章:

    相关文章

      网友评论

        本文标题:Pinia快速入门-上手指南

        本文链接:https://www.haomeiwen.com/subject/gofzprtx.html