vue状态管理之pinia

189 阅读2分钟

前言

  • 支持vue2和vue3
  • 安装: npm i pinia

相比于vuex

  • Vuex
    • 优点
      • 支持调试功能,如时间旅行和编辑
      • 适用于大规模和高复杂性的Vue.js项目
    • 缺点
      • 从 Vue3 开始,getter的结果不会像计算属性那样被缓存起来
      • Vuex4 有一些与类型安全相关的问题
  • Pinia
    • 优点
      • 体积更小
      • 能更好的支持ts
      • 没有mutation,全都放在 action 中了
      • action 被调度为常规的函数调用,而不是使用 dispatch方法 或 MapAction 辅助函数
      • 支持多个Store
      • 支持 Vue devtools、SSR 和 webpack 代码拆分
    • 缺点
      • 不支持时间旅行和编辑等调试功能

基本使用

  1. 在main.ts中注册
import { createPinia } from 'pinia';

app.use(createPinia());
  1. 在store/index.ts管理状态
import { defineStore } from 'pinia';

// 返回一个函数
export const useMainStore = defineStore({
  // id必须在所有 Store 中唯一
  id: "globalState",
  // 必须是箭头函数: 为了更好的使用ts
  state: () => ({
    count: 1
  }),
});
  1. 在组件中使用方式一
<template>
  <div>
    // 使用state数据
    {{ mainStore.count }}
  </div>
</template>

<script>
  // 导入 Store
  import { useMainStore } from '@/store/index.ts';

  export default {
    setup() {
      // 调用Store函数,获得Store实例
      const mainStore = useMainStore();

      return {
        mainStore
      }
    }
  }
</script>
  1. 在组件中使用方式二: 使用storeToRefs解构
<template>
  <div>
    // 使用state数据
    {{ count }}
  </div>
</template>

<script>
  import { storeToRefs } from 'pinia';
  import { useMainStore } from '@/store/index.ts';

  export default {
    setup() {
      const mainStore = useMainStore();
      // const { count } = mainStore // 非响应式
      // js中使用: count.value
      const { count } = storeToRefs(mainStore) // 响应式

      return {
        count
      }
    }
  }
</script>

修改数据(action)

export const useMainStore = defineStore({
  id: "globalState",
  state: () => ({
    count: 1,
    foo: 'hi',
    arr: [1, 2, 3]
  }),
  // 同步异步都可以写在这里
  action: {
    changeState(num) {
      this.count++
      this.foo = 'hello'
      this.arr.push(num)
      // this.$patch({})
      // this.$patch(state => {})
    }
  }
});

setup() {
  const mainStore = useMainStore();
  const { count, foo, arr } = storeToRefs(mainStore)

  const handleChangeState = () => {
    // 方式一: 多次修改,性能较差
    mainStore.count++
    mainStore.foo = 'hello'
    mainStore.arr.push(4)

    // 方式二: 批量更新
    mainStore.$patch({
      count: mainStore.count + 1
      foo: 'hello',
      arr: [...mainStore.arr, 4]
    })

    // 方式三: 更好的批量更新方式
    mainStore.$patch(state => {
      state.count++
      state.foo = 'hello'
      state.arr.push(4)
    })

    // 方式四: action中修改
    mainStore.changeState(4)
  }

  return {
    count,
    foo,
    arr
  }
}

getters

类似于计算属性,与vuex中的用法一致

export const useMainStore = defineStore({
  id: "globalState",
  state: () => ({
    count: 1,
  }),
  getters: {
    count10(state) {
      // return this.count + 10 // 也可以直接用this
      return state.count + 10
    }
  }
});

模块化

  • store/user.js

    import { defineStore } from 'pinia'
    
    const useUserStore = defineStore('user', {
      state: () => {
        name: 'zs',
        age: 100,
      },
    })
    
    export default useUserStore
    
  • store/index.js

    import useUserStore from './user'
    import useCounterStore from './counter'
    
    // 统一导出useStore方法
    export default function useStore() {
      return {
        user: useUserStore(),
        counter: useCounterStore(),
      }
    }
    
  • 在组件中使用

    import { storeToRefs } from 'pinia'
    import useStore from './store'
    
    const { counter } = useStore()
    const { count, double } = storeToRefs(counter)
    

数据持久化

  • 安装: npm i pinia-plugin-persistedstate

  • main.ts中配置插件

    import { createPinia } from 'pinia'
    import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
    
    const pinia = createPinia()
    pinia.use(piniaPluginPersistedstate)
    app.use(pinia)
    
  • 数据持久化

    import { defineStore } from 'pinia'
    
    export const useUserStore = defineStore('main', {
      state: () => {
        someState: 'hello pinia',
        nested: {
          data: 'nested pinia',
        },
      },
      // 所有数据持久化
      // persist: true,
      persist: {
        // 修改存储中使用的键名称,默认为当前 store 的 id
        key: 'storekey',
        // 修改为存储方式,默认为 localStorage
        storage: window.sessionStorage,
        // 按需持久化部分数据,[]意味着没有状态被持久化(默认为undefined,持久化整个状态)
        paths: ['nested.data'],
      },
    })
    

参考