vue.js Pinia中的继承/共享操作和getter

mpbci0fu  于 2022-11-17  发布在  Vue.js
关注(0)|答案(1)|浏览(223)

我有几个Pinia商店,它们应该共享一组操作和getter,我不太确定如何有效地实现这一点。
我正在开发一个应用程序,让用户可以管理大量不同的媒体(书籍、电影、电视节目等)。我目前考虑的方式是为每种媒体类型(如书店、电影店等)建立一个商店。这些不同商店之间的许多getter和操作(如countdeleteOne)完全相同。
我如何在这里实现DRY?Pinia文档中有一些例子,主要集中在重用其他存储中的操作和getter,但我不认为这完全解决了我的完全继承一组getter和setter的用例。
我在这里尝试的继承方法是反模式吗?

qlvxas9a

qlvxas9a1#

这可以使用docs插件实现

示例影片:

您有多个商店对每个州使用共享命名方案:

  • item:单个实体项(单个影片详细信息)
  • collection:项目集合(所有影片的集合)

每个商店都有相同的CRUD操作,只有URL发生变化

  • 获取集合:从API获取项目列表并将响应设置为集合(https://url.com/movies
  • getItem:从API获取单个项目并将响应设置为项目(https://url.com/movies/id
  • 句柄错误:向用户显示带有错误信息的警报
    创建插件:
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);
        },
    };
}
  • 给予Pinia插件:**
const pinia = createPinia();

pinia.use(BaseStorePlugin);

示例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);
                });
        },
    },
});

组件中的使用示例

<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>

编辑: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}`
          });
        });
      },
    };
  };
}

我已经创建了一个非常基本的例子,使用3个商店和上面的检查代码andbox here

相关问题