跳至主要內容

pinia 全局状态共享

Entity大约 4 分钟

pinia 全局状态共享

安装pinia

npm install pinia

vue

import { createPinia } from 'pinia'

vue.use(createPinia());

使用store

import { defineStore } from 'pinia'

// 按照规定应该以use开头 use...
// 第一个参数是store的唯一id
export const useStore = defineStore('main',{
    state : ()={
        return{
            // 所有这些属性都将自动推断其类型
            count:0
        }
    }
});

访问刚才定义的store

import { useStore } from 'useStore';
export default defineComponent({
    setup(){
        // 不能这样会失去响应式属性
        const data = useStore();
        // 应该这样
        const { count } = useStore();
    }
})

访问store

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

改变状态

const store = useStore();
store.count++;
// 除了直接使用count++ ,您还可以使用$patch方法
store.$patch({
    count : 1
});

但是,使用这种语法应用某些突变非常困难或代价高昂:任何集合修改(例如,从数组中推送、删除、拼接元素)都需要您创建一个新集合。 正因为如此,$patch 方法也接受一个函数来批量修改集合内部分对象的情况:

store.$patch((state)=>{
    state.count = 1;
    state.hasChanged = true;
});

替换state

store.$state = {count : 999};

还可以通过更改pinia实例的state来替换应用程序的整个状态

pinia.state.value = {count : 999};

订阅状态

可以通过store的$subscribe() 方法查看状态及变化

store.$subscribe((mutation, state)=>{
    mutation.type // 'direct' | 'patch object' | 'patch function'
    // 与Store.$id相同
    mutation.storeId // 'main'

    // 当他发生变化时,将整个状态持久化到本地存储
    localStorage.setItem('main',JSON.stringify(state));
});

默认情况下,state subscriptions 绑定到添加它们的组件(如果 store 位于组件的 setup() 中)。 意思是,当组件被卸载时,它们将被自动删除。 如果要在卸载组件后保留它们,请将 { detached: true } 作为第二个参数传递给 detach 当前组件的 state subscription:

export default {
  setup() {
    const someStore = useSomeStore()

    // 此订阅将在组件卸载后保留
    someStore.$subscribe(callback, { detached: true })

    // ...
  },
}

提示

您可以在 pinia 实例上查看整个状态:

watch(
  pinia.state,
  (state) => {
    // 每当它发生变化时,将整个状态持久化到本地存储
    localStorage.setItem('piniaState', JSON.stringify(state))
  },
  { deep: true }
)

storeToRefs

import { useStore } from 'useStore'
import { storeToRefs } from 'pinia'
const { count } = storeToRefs(useStore());

Getters

export const useStore = defineStore('main',{
    state:()=>({
        counter: 0
    }),
    getters:{
        GetCounter : (state)=>state.counter * 2
    }
});

action 相当于组件中的methods。

import { defineStore } from 'pinia';

const useStore = defineStore('main',{
    state:()=>({
        counter: 0
    }),
    actions: {
        increment(){
            this.counter++;
        }
    }
});

使用 setup()

import { useStore } from 'useStore';

export default {
    setup(){
        const data = useStore();
        data.increment();
    }
}

使用 setup()

import { useStore } from 'useStore';

export default {
    setup(){
        const data = useStore();
        
        return {
            data
        }
    },
    methods: {
        incrementAndPoint(){
            data.increment();
            console.log(`New Counter: ${data.counter}`);
        }
    }
}

不使用setup

mapActions

通过生成一个传递到组件的 methods 字段的对象, 允许直接使用 store 的 action,而不需要使用组合式 API(setup())。 该对象的值是 action, 而键是产生的方法名称。

import { mapActions } from 'pinia'
import { useStore } from 'useStore';

export default{
    methods:{
        ...mapActions(useStore,['increment']),
        ...mapActions(useStore,{NewIncrement: 'increment'}),
    },
    create(){
        this.increment();
        this.NewIncrement();
    }
}

订阅Actions

可以使用 store.$onAction() 订阅 action 及其结果。 传递给它的回调在 action 之前执行。 after 处理 Promise 并允许您在 action 完成后执行函数。 以类似的方式,onError 允许您在处理中抛出错误。 这些对于在运行时跟踪错误很有用,类似于 Vue 文档中的这个提示。

这是一个在运行 action 之前和它们 resolve/reject 之后记录的示例。

const unsubscribe = someStore.$onAction(
  ({
    name, // action 的名字
    store, // store 实例
    args, // 调用这个 action 的参数
    after, // 在这个 action 执行完毕之后,执行这个函数
    onError, // 在这个 action 抛出异常的时候,执行这个函数
  }) => {
    // 记录开始的时间变量
    const startTime = Date.now()
    // 这将在 `store` 上的操作执行之前触发
    console.log(`Start "${name}" with params [${args.join(', ')}].`)

    // 如果 action 成功并且完全运行后,after 将触发。
    // 它将等待任何返回的 promise
    after((result) => {
      console.log(
        `Finished "${name}" after ${
          Date.now() - startTime
        }ms.\nResult: ${result}.`
      )
    })

    // 如果 action 抛出或返回 Promise.reject ,onError 将触发
    onError((error) => {
      console.warn(
        `Failed "${name}" after ${Date.now() - startTime}ms.\nError: ${error}.`
      )
    })
  }
)

// 手动移除订阅
unsubscribe()

持久化存储

安装pinia-plugin-persistedstate

npm install pinia-plugin-persistedstate

vue.use()

import {
	createSSRApp
} from "vue";
import { createPinia } from 'pinia'
import { createPersistedState } from 'pinia-plugin-persistedstate'

import App from "./App.vue";
export function createApp() {
	const app = createSSRApp(App);
	const pinia = createPinia();
    // 设置全局配置
	pinia.use(createPersistedState({
		storage:{
			setItem:(key, value)=>uni.setStorageSync(key, value),
			getItem: (key)=>uni.getStorageSync(key),
			clear:()=>uni.clearStorageSync()
		}
	}));
	app.use(pinia);
	return {
		app,
	};
}

persistedstate config

import { defineStore } from 'pinia'

export const useStore = defineStore('store', {
  state: () => ({
    save: {
      me: 'saved',
      notMe: 'not-saved',
      list:[
        {a:'12134'},
        {a:'12134'},
        {a:'12134'},
      ]
    },
    saveMeToo: 'saved',
  }),
  persist: {
    // 键值
    key:'pinia_main',
    // 表示需要保存的节点,表示不保留任何状态,或表示保留整个状态
    // 若要存储数组的所有元素,请使用表示法‘【】’
    paths: ['save.me', 'saveMeToo','list.[].a'],
  },
})