Pinia 中的继承/共享操作和吸气剂

Dan*_*ter 6 inheritance vue.js pinia

我有几个 Pinia 商店应该共享一组操作和 getter,但我不太确定如何有效地实现这一点。

\n

I\xe2\x80\x99m 构建一个应用程序,让用户管理多种不同的媒体(书籍、电影、电视节目等)。我\xe2\x80\x99m 目前考虑的方式是为每种媒体类型创建一个存储,例如 BookStore、MovieStore 等。这些不同存储之间的许多 getter 和操作(例如countdeleteOne)完全相同。

\n

我如何在这里实现 DRY?Pinia文档中的示例主要集中在其他商店内重用操作和 getter,但我不\xe2\x80\x99t 认为这完全解决了我直接继承一组 getter 和 setter 的用例。

\n

我在这里尝试的继承方法是反模式吗?

\n

Mul*_*lti 5

This is achievable using plugins docs

Example Movies:

You have multiple stores using shared naming scheme for each state:

  • item: single entity item (single movie details)
  • collection: collection of items (collection of all movies)

each store will have the same CRUD actions with only the URL changing

  • getCollection: get list of items from API and set response as collection (https://url.com/movies)
  • getItem:从 API 获取单个项目并将响应设置为项目 ( https://url.com/movies/id )
  • handleError:向用户显示带有错误信息的警报

创建插件:

function BaseStorePlugin () {
    return {
        collection: [],
        item: {},
        getCollection: function (url) {
            api.get(url)
                .then((response) => {
                    this.collection = response.data;
                })
                .catch((error) => {
                    this.handleError(error);
                });
        },
        getItem: function (url) {
            api.get(url)
                .then((response) => {
                    this.item = response.data;
                })
                .catch((error) => {
                    this.handleError(error);
                });
        },
        handleError: function (error) {
            window.alert(error);
        },
    };
}
Run Code Online (Sandbox Code Playgroud)

给 Pinia 提供插件:

const pinia = createPinia();

pinia.use(BaseStorePlugin);
Run Code Online (Sandbox Code Playgroud)

示例 movieStore.js(使用共享操作和状态)

import { defineStore } from 'pinia';
import { api } from 'src/boot/axios';

export const useMovieStore = defineStore({
    id: 'movie',
    state: () => ({
        movieSpecificStateObject: {},
    }),
    actions: {
        movieSpecificAction (url) {
            console.log(this.item);
            api.get(url)
                .then((response) => {
                    // handle response
                })
                .catch((error) => {
                    this.handleError(error);
                });
        },
    },
});
Run Code Online (Sandbox Code Playgroud)

组件中的用法示例

<template>
    <div
        v-for="movie in movieStore.collection"
        :key="movie.id"
    >
        <div>
            {{ movie.name }}
        </div>
    </div>
</template>

<script setup>
import { onMounted } from 'vue';
import { useMovieStore } from 'src/stores/movieStore.js';
const movieStore = useMovieStore();

onMounted(() => {
    movieStore.readCollection('http://url.com/movies');
});
</script>
Run Code Online (Sandbox Code Playgroud)

编辑:1

如果您将上下文传递到插件中,您就可以访问商店和传递给其中的选项,从中您可以检查商店 ID,并且仅返回特定商店,如下所示

function BaseStorePlugin (context) {
  const allowedStores = ['movie', 'album'];

  if (allowedStores.includes(context.store.$id)) {
    return {
      collection: [],
      getCollection: function () {
        const fakeCollection = Array.from({length: 10}, () => Math.floor(Math.random() * 40));
        fakeCollection.forEach((item) => {
          this.collection.push({
            id: item,
            name: `name${item}`
          });
        });
      },
    };
  };
}
Run Code Online (Sandbox Code Playgroud)

我使用 3 个商店创建了一个非常基本的示例,上面的检查可在 codeandbox 上找到