美文网首页
Pinia or Vuex?

Pinia or Vuex?

作者: cyh_1 | 来源:发表于2022-11-17 17:50 被阅读0次

    Pinia是什么?

    官网解释:

    Pinia 是 Vue 的存储库,它允许您跨组件/页面共享状态。

    从官网的解释不难看出,Pinia和Vuex的作用是一样的,它也充当的是一个存储数据的作用,存储在Pinia的数据允许我们在各个组件中使用。

    实际上,Pinia就是Vuex的升级版,官网也说过,为了尊重原作者,所以取名Pinia,而没有取名Vuex,所以可以将Pinia比作为Vue3的Vuex。

    Pinia的使用

    1. 安装pinia

    npm install pinia
    

    2. 引入pinia

    vue3 中引入的使用

    import { createApp } from 'vue'
    import App from './App.vue'
    import { createPinia } from 'pinia'
    const app = createApp(App)
    const pinia = createPinia()
    app.use(pinia);
    app.mount('#app')
    

    vue2 中引入的使用

    import { createPinia } from 'pinia'
    const pinia = createPinia()
    new Vue({
      el: '#app',
      // 其他选项...
      // ...
      pinia,
    })
    

    3. Store

    3.1 定义store

    创建 store/user.js

    import { defineStore } from 'pinia'
    export const useStore = defineStore({
        id: 'user',
        state: () => ({
            count: 0,
            username: '10个肉包子'
        }),
        getters: {},
        actions: {},
    })
    

    3.2 使用store

    <script setup>
    import storeUser from "@/store/user";
    const { counter } = storeUser();
    console.log(123, count);
    </script>
    

    4. State

    4.1 定义state

    export default defineStore('user', {
        state: () => ({
            count: 0,
            username: '10个肉包子'
        }),
    });
    

    4.2 使用state

    • 方法 1. 直接获取

    以 javascript 中的模块导出的方式导出 store 数据,state 中的数据均可通过变量.state 数据名获取

    <script setup>
    import storeUser from "@/store/user";
    const { counter } = storeUser();
    console.log(123, count);
    </script>
    
    • 方法 2. 解构获取

    store 是一个 reactive 响应式对象,直接解构会使其失去响应式,类似 setup 中的 props,为了既可解构又可保持其响应式,可使用 storeToRefs,它将为每个 reactive 属性创建 refs

    <script setup>
    import { storeToRefs } from "pinia";
    import storeUser from "@/store/user";
    const { count } = storeToRefs(storeUser());
    console.log(123, count);
    </script>
    <template>
        <div>
            {{ count }}
        </div>
    </template>
    

    4.3 修改 state

    • 直接修改 state:
    <script setup>
    import storeUser from "@/store/user";
    const store = storeUser();
    store.count++
    console.log(123, store);
    </script>
    
    • $patch 已对象修改
    <template>
      <div>index-{{store.count}}</div>
    </template>
    <script setup>
    import storeUser from "@/store/user";
    const store = storeUser();
    store.$patch({
      count: 3,
    });
    </script>
    

    缺点: 如果只需修改 state 数据中的某一项,仍然需要将整个对象传给 store。

    或者

    <template>
      <div>index-{{store.count}}</div>
    </template>
    <script setup>
    import storeUser from "@/store/user";
    const store = storeUser();
    store.$patch({
      count: 3,
    });
    </script>
    

    4.4 替换state

    <template>
      <div>index-{{store.count}}</div>
    </template>
    <script setup>
    import storeUser from "@/store/user"
    const store = storeUser()
    store.$state = { count: 666, username: 'Paimon' }
    </script>
    

    4.5 重置state

    一键回复默认的 state 数据

    <template>
      <div>index-{{store}}</div>
    </template>
    
    <script setup>
    import storeUser from "@/store/user"
    const store = storeUser()
    
    store.$patch({
      count: 3,
    });
    setTimeout(() => {
      store.$reset()
    }, 3000)
    console.log(123, store)
    </script>
    

    5. Getters

    5.1 获取数据

    建议使用尖头函数

    export const useStore = defineStore('user', {
      state: () => ({
        counter: 0,
      }),
      getters: {
        doubleCount: (state) => state.counter * 2,
      },
    })
    
    <template>
        <div> {{ doubleCount }} </div>
        <div> {{ counter }} </div>
    </template>
    <script setup>
    import storeUser from "@/store/user"
    import { storeToRefs } from 'pinia'
    const store = storeUser();
    const { doubleCount, counter } = storeToRefs(storeUser())
    </script>
    

    5.2 访问其他 getters

    访问其他的 getter 需要使用 this, 注意:不能使用尖头函数了

    export const useStore = defineStore('user', {
      state: () => ({
        counter: 0,
      }),
      getters: {
        doubleCount(state) {
          return state.counter * 2
        },
        doublePlusOne() {
          return this.doubleCount + 1
        },
      },
    })
    

    5.3 getters 传递参数

    export const useStore = defineStore('user', {
      getters: {
        getUserById: (state) => {
          return (userId) => state.users.find((user) => user.id === userId)
        },
      },
    })</pre>
    
    <pre data-language="plain" id="tPS6e" class="ne-codeblock language-plain" style="border: 1px solid #e8e8e8; border-radius: 2px; background: #f9f9f9; padding: 16px; font-size: 13px; color: #595959"><template>
      <p>User 2: {{ store.getUserById(2) }}</p>
    </template>
    <script setup>
    import storeUser from "../../store/user";
    const store = storeUser();
    </script>
    

    注意: getters are not cached anymore 即 getters 不会被缓存,只能函数调用。

    5.4 访问其他的 getter

    即想要哪个 getters 则调用哪个 getter,因为 pinia 没有总入口,和 vuex 有本质区别。

    import { useOtherStore } from './other-store'
    
    export const useStore = defineStore('main', {
      state: () => ({
        // ...
      }),
      getters: {
        otherGetter(state) {
          const otherStore = useOtherStore()
          return state.localData + otherStore.data
        },
      },
    })
    

    5.5 使用 mapState 访问 store 中的数据

    import { mapState } from 'pinia'
    import storeUser from "@/store/user";
    
    export default {
      computed: {
        ...mapState(storeUser, ['doubleCount'])
        ...mapState(storeUser, {
          myOwnName: 'doubleCounter',
          double: state => state.doubleCount,
        }),
      },
    }
    

    6. Actions

    6.1 获取方法

    export const useStore = defineStore('user', {
      state: () => ({
        count: 0,
      }),
      actions: {
        increment() {
          this.count++
        },
        randomizeCounter() {
          this.count = Math.round(100 * Math.random())
        },
      },
    })
    

    6.2 使用方法

    • 同步的方式
    <script setup>
    import storeUser from "@/store/user"
    const store = storeUser()
    </script>
    <template>
        <button @click="store.increment()">增加</button>
    </template>
    
    • 异步的方式
    import { mande } from 'mande'
    const api = '@/api/users'
    export const useUsers = defineStore('users', {
      state: () => ({
        userData: {},
      }),
    
      actions: {
        async registerUser(login, password) {
          try {
            this.userData = await api.post({ login, password })
            console.info(`Welcome back ${this.userData.name}!`)
          } catch (error) {
             console.error(error)
            return error
          }
        },
      },
    })
    

    Pinia 数据持久化插件

    1. 安装

    npm i pinia-plugin-persist
    

    2. 引入

    Vue2中引入使用

    import Vue from 'vue'
    import vueCompositionApi from '@vue/composition-api'
    import { createPinia } from 'pinia'
    import piniaPersist from 'pinia-plugin-persist'
    import App from './App.vue'
    
    const pinia = createPinia()
    pinia.use(piniaPersist)
    
    Vue.use(vueCompositionApi)
    Vue.use(pinia)
    
    new Vue({
      pinia,
      render: h => h(App),
    }).$mount('#app')
    

    Vue3中引入使用

    import { createApp } from 'vue'
    import { createPinia } from 'pinia'
    import piniaPersist from 'pinia-plugin-persist'
    
    const pinia = createPinia()
    pinia.use(piniaPersist)
    
    createApp({})
      .use(pinia)
      .mount('#app')
    

    Pinia持久化插件用法

    pinia的优点

    1. Vue2和Vue3都支持,这让我们同时使用Vue2和Vue3的小伙伴都能很快上手。

    2. Pinia中只有state、getter、action,抛弃了Vuex中的Mutation,pinia直接抛弃它了,这无疑减少了我们工作量。

    3. Pinia中action支持同步和异步,Vuex不支持

    4. 良好的Typescript支持,Vue3都推荐使用TS来编写,这个时候使用Pinia就非常合适了

    5. 无需再创建各个模块嵌套了,Vuex中如果数据过多,我们通常分模块来进行管理,稍显麻烦,而pinia中每个store都是独立的,互相不影响。 image
    6. 体积非常小,只有1KB左右。

    7. pinia支持插件来扩展自身功能。

    8. 支持服务端渲染。

    Pinia 与 Vuex对比

    Pinia:State、Gettes、Actions(同步异步都支持)

    Pinia图解:


    image

    Vuex:State、Gettes、Mutations(同步)、Actions(异步)

    Vuex图解:


    image

    Pinia 当前最新版是 2.x,即支持 Vue2 也支持 Vue3;Vuex 当前最新版是 4.x,Vuex4 用于 Vue3,Vuex3 用于 Vue2。

    相关文章

      网友评论

          本文标题:Pinia or Vuex?

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