Pinia入门笔记

228 阅读1分钟

前言

在开发Vue3时发现越来越多的人开始使用Pinia,它的好处就不说了,官网很详细。

本文的目的是帮助自己学习Pinia

安装

在之前的一篇文章中我已经写过如何安装它,也可以直接看官网的安装教程,这里不过多阐述

使用

  1. 一种常规的使用方法就是类似于vuex,如:
// test.ts
import { defineStore } from 'pinia';

export const useTestStore = defineStore('test', {
    state: () => {
        return {
            name: 'xiaoming',
            age: 18
        }
    }
});
  1. 类似Vue3一样的写法
// test.ts
import { defineStore } from 'pinia';
import { ref } from 'vue';

export const useTestStore = defineStore('test', () => {
    const name = ref('xiaoming');
    const age = ref(18);

    return {
        name,
        age
    }
});

修改state的5种方式

  1. 直接用对象修改
  2. $patch(args)
  3. $patch(() => args)
  4. $state
  5. actions内的方法修改
<template>
    <p>name: {{ test.name }}, age: {{ test.age }}</p>
    <button class="px-4 border-2 border-solid border-black" @click="changeInfo">change</button>
</template>

<script setup lang="ts">
import { useTestStore } from '@/piniaStore/test';

const test = useTestStore()
const changeInfo = () => {
    // 1. 直接修改
    test.name = 'laoli';

    // 2. $patch
    // test.$patch({
    //     name: 'laoli'
    // });

    // 3. $patch,用于一些条件的判断
    // test.$patch((state) => {
    //     state.name = 'laoli';
    // });

    // 4. $state,必须全部都要赋值,不能单独一个
    // test.$state = {
    //     name: 'laoli',
    //     age: 18
    // }

    // 5. pinia的actions方式
    // test.setName('laoli');
}
</script>

其中第5种方式的actions写法为:

// test.ts
import { defineStore } from 'pinia';

export const useTestStore = defineStore('test', {
    // ...
    actions: {
        setName(name: string) {
            this.name = name;
        }
    }
});

解构

<template>
    <p>name: {{ test.name }}, age: {{ test.age }}</p>
    <p>name: {{ name }}, age: {{ age }}</p>
    <button class="px-4 border-2 border-solid border-black" @click="changeInfo">change</button>
</template>

<script setup lang="ts">
import { useTestStore } from '@/piniaStore/test';
import { storeToRefs } from 'pinia';
// import { toRefs } from 'vue';

const test = useTestStore()
const { name, age } = storeToRefs(test)
// const { name, age } = toRefs(test) // 也可以使用vue3的toRefs

const changeInfo = () => {
    // 1. 还是原对象改变
    // test.name = 'laoli';
    // 2. 直接使用结构对象改变
    name.value = 'laoli';
}
</script>

getters & actions用法

import { defineStore } from 'pinia';

interface User {
    name: string;
    age: number;
}

const asyncSetName = () => {
    return new Promise<User>((resolve) => {
        setTimeout(() => {
            resolve({
                name: 'laowang',
                age: 20
            })
        }, 2000);
    })
}

export const useTestStore = defineStore('test', {
    state: () => {
        return {
            name: 'xiaoming',
            age: 18
        }
    },
    getters: {
        personInfo({ name, age }) {
            return `name: ${name}, age: ${age}`;
        }
    },
    actions: {
        async setName() {
            const { name, age } = await asyncSetName();
            this.name = name;
            this.age = age;
        }
    }
});

公共方法

  • $subscribe:state改变时触发该函数内的回调函数
  • $reset:state恢复原始值
  • $onAction:actions改变时触发该函数内的回调函数
<template>
    <p>name: {{ test.name }}, age: {{ test.age }}</p>
    <button class="px-4 border-2 border-solid border-black" @click="changeInfo">change</button>
    <br>
    <button class="px-4 border-2 border-solid border-black" @click="onReset">reset</button>
</template>

<script setup lang="ts">
import { useTestStore } from '@/piniaStore/test';

const test = useTestStore()

const changeInfo = () => {
    test.setName();
}

// state改变时触发该回调函数
test.$subscribe((args, state) => {
    console.log(args, state);
});

// actions改变时触发该回调函数
test.$onAction((args) => {
    console.log(args);
});

const onReset = () => {

    // 恢复到原来的状态
    test.$reset();
}
</script>

持久化

  1. 使用$subscribe监听state变化
  2. 一开始加载时读取数据
import type { PiniaPluginContext } from 'pinia';

import { createApp, toRaw } from 'vue';
import App from './App.vue';
import { createPinia } from 'pinia';

interface PluginOptions {
    key: string;
}

const setData = (key: string, value: unknown) => {
    localStorage.setItem(key, JSON.stringify(value));
}

const getData = (key: string) => {
    let value = localStorage.getItem(key);
    let parseVal = {}
    try {
        parseVal = JSON.parse(value || '{}');
    } catch {
        console.error('parse error');
    }

    return parseVal
}

const createPlugin = (options: PluginOptions) => {
    const { key } = options;

    return (context: PiniaPluginContext) => {
        const { store } = context

        // 保存state值
        store.$subscribe(() => {
            setData(key, toRaw(store.$state));
        });

        // 获取state值
        const state = getData(key);
        return state;
    }
}

const app = createApp(App);
const store = createPinia();
store.use(createPlugin({
    key: 'testPlugin'
}));

app.use(store);
app.mount('#app');

问题:如果使用setup的方式声明变量,暂时还不知道如何取数据才能拿到所有的$state,有知道的告诉我一下

参考来源