vue3最佳全局状态管理工具-Pinia

144 阅读3分钟

pinia 的使用

概述

现有用户可能对 Vuex 更熟悉,它是 Vue 之前的官方状态管理库。由于 Pinia 在生态系统中能够承担相同的职责且能做得更好,因此 Vuex 现在处于维护模式。它仍然可以工作,但不再接受新的功能。对于新的应用,建议使用 Pinia

事实上,Pinia 最初正是为了探索 Vuex 的下一个版本而开发的,因此整合了核心团队关于 Vuex 5 的许多想法。最终,我们意识到 Pinia 已经实现了我们想要在 Vuex 5 中提供的大部分内容,因此决定将其作为新的官方推荐。

相比于 VuexPinia 提供了更简洁直接的 API,并提供了组合式风格的 API,最重要的是,在使用 TypeScript 时它提供了更完善的类型推导。

安装

yarn add pinia
# or with npm
npm install pinia

创建一个 pinia 实例

import { createApp } from "vue";
import { createPinia } from "pinia";
import App from "./App.vue";

const pinia = createPinia();
const app = createApp(App);

app.use(pinia);
app.mount("#app");

定义一个 store

1.选项式

//您可以将`defineStore()`的返回值命名为任意名称,

//但最好使用store的名称,并用“use”将其包围

//(例如`useUserStore`、`useCartStore`和`useProductStore`)

//第一个参数是应用程序中存储的唯一id
export const useCounterStore = defineStore("counter", {
  //与 Vue 的选项 API 类似,我们也可以传递带有属性的选项对象。state actions getters
  state: () => ({ count: 0, name: "Eduardo" }),
  getters: {
    doubleCount: (state) => state.count * 2,
  },
  actions: {
    increment() {
      this.count++;
    },
  },
});

2.组合式

import { defineStore } from "pinia";
// 你可以这样记忆
//state => data
//getters => computed
//actions => methods
export const useCounterStore = defineStore("counter", () => {
  const count = ref(0);
  const name = ref("Eduardo");
  const doubleCount = computed(() => count.value * 2);
  function increment() {
    count.value++;
  }

  return { count, name, doubleCount, increment };
});

使用

import { useCounterStore } from "@/stores/counter";
import { storeToRefs } from "pinia";
export default {
  setup() {
    const store = useCounterStore();
    //结构并赋予响应性
    const { name, doubleCount } = storeToRefs(store);
    return {
      // you can return the whole store instance to use it in the template
      store,
    };
  },
};

state

//给 state 加上类型推导
export const useUserStore = defineStore("user", {
  state: () => {
    return {
      userList: [] as UserInfo[],
      user: null as UserInfo | null,
    };
  },
});

interface UserInfo {
  name: string;
  age: number;
}
//或者给整个state加上类型推导
interface State {
  userList: UserInfo[];
  user: UserInfo | null;
}

export const useUserStore = defineStore("user", {
  state: (): State => {
    return {
      userList: [],
      user: null,
    };
  },
});

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

访问 state

const store = useStore();

store.count++;

重置状态

const store = useStore();

store.$reset();

改变 state

//1.直接改变
store.count++;
//2.$patch
store.$patch({
  count: store.count + 1,
  age: 120,
  name: "DIO",
});
//或
cartStore.$patch((state) => {
  state.items.push({ name: "shoes", quantity: 1 });
  state.hasChanged = true;
});

getters

定义

export const useCounterStore = defineStore("counter", {
  state: () => ({
    count: 0,
  }),
  getters: {
    doubleCount: (state) => state.count * 2,
  },
});
//添加类型约束
export const useCounterStore = defineStore("counter", {
  state: () => ({
    count: 0,
  }),
  getters: {
    // automatically infers the return type as a number
    doubleCount(state) {
      return state.count * 2;
    },
    // the return type **must** be explicitly set
    doublePlusOne(): number {
      // autocompletion and typings for the whole store ✨
      return this.doubleCount + 1;
    },
  },
});

访问

<template>
  <p>Double count is {{ store.doubleCount }}</p>
</template>

<script>
export default {
  setup() {
    const store = useCounterStore();

    return { store };
  },
};
</script>

访问其他 getter

export const useCounterStore = defineStore("counter", {
  state: () => ({
    count: 0,
  }),
  getters: {
    doubleCount: (state) => state.count * 2,
    doubleCountPlusOne() {
      // autocompletion ✨
      return this.doubleCount + 1;
    },
  },
});

将参数传递给获取者

export const useStore = defineStore('main', {
  getters: {
    getUserById: (state) => {
      return (userId) => state.users.find((user) => user.id === userId)
    },
  },
})
//组件中使用
<script>
export default {
  setup() {
    const store = useStore()

    return { getUserById: store.getUserById }
  },
}
</script>

<template>
  <p>User 2: {{ getUserById(2) }}</p>
</template>

actions

定义

export const useCounterStore = defineStore("counter", {
  state: () => ({
    count: 0,
  }),
  actions: {
    // 因为我们依赖“this”,所以不能使用箭头函数
    increment() {
      this.count++;
    },
    randomizeCounter() {
      this.count = Math.round(100 * Math.random());
    },
  },
});
//与 getter 一样,操作通过完全键入(和自动完成✨)支持来访问整个商店实例。与 getter 不同,操作可以是异步的
import { mande } from "mande";

const api = mande("/api/users");

export const useUsers = defineStore("users", {
  state: () => ({
    userData: null,
    // ...
  }),

  actions: {
    async registerUser(login, password) {
      try {
        this.userData = await api.post({ login, password });
        showTooltip(`Welcome back ${this.userData.name}!`);
      } catch (error) {
        showTooltip(error);
        // let the form component display the error
        return error;
      }
    },
  },
});

使用

export default {
  setup() {
    const store = useCounterStore();

    store.randomizeCounter();
  },
};