Maison  >  Questions et réponses  >  le corps du texte

Héritage/opérations partagées et getters à Pinia

J'ai plusieurs magasins Pinia qui sont censés partager un ensemble d'opérations et de getters, mais je ne sais pas trop comment y parvenir efficacement.

Je développe une application qui permet aux utilisateurs de gérer de nombreux médias différents (livres, films, émissions de télévision, etc.). La façon dont j'y pense actuellement est d'avoir un magasin pour chaque type de média, tel que BookStore, MovieStore, etc. De nombreux getters et opérations (comme countdeleteOne) sont exactement les mêmes entre ces différents magasins.

Comment implémenter DRY ici ? Les exemples de la documentation Pinia se concentrent sur la réutilisation d'actions et de getters dans d'autres magasins, mais je ne pense pas que cela réponde pleinement à mon cas d'utilisation consistant à hériter directement d'un ensemble de getters et de setters.

L'approche successorale que j'essaie ici est-elle un anti-modèle ?

P粉662614213P粉662614213302 Il y a quelques jours472

répondre à tous(2)je répondrai

  • P粉420958692

    P粉4209586922023-12-23 12:54:52

    Si vous souhaitez que certaines fonctionnalités ne soient pas partagées dans tous les magasins, vous pouvez utiliser composable.

    Vous pouvez créer une fonction composable distincte et y transmettre une partie de l'instance du magasin.

    J'ai fait un exemple pour vous sur codesandbox.

    Voici un court exemple de codesandbox :

    common.ts

    import { computed, Ref, ref } from "vue";
    
    export function useCommon(initValue: number) {
        const _value = ref<number>(initValue);
    
        function increment() {
            _value.value++;
        }
    
        function someProcessing() {
            // ... some code here
        }
    
        return {
            counter,
    
            increment,
            someProcessing,
        };
    }

    Ensuite, dans n'importe quel magasin, vous pouvez l'utiliser comme ceci :

    fooStore.ts

    export const useFooStore = defineStore('foo', () => {
        const state = ref<string>('foo');
    
        const { counter, increment, someProcessing } = useCounter(0);
    
        return {
            state,
    
            counter,
            increment,
            someProcessing,
        }
    }

    De cette façon, vous pouvez composer n'importe quelle fonction, objet, etc. dans n'importe quel stockage ou dans n'importe quel composant.

    répondre
    0
  • P粉449281068

    P粉4492810682023-12-23 00:43:42

    Cela peut être réalisé à l'aide de plugins docs

    Exemple de film :

    Vous possédez plusieurs magasins, chaque état utilisant un schéma de dénomination partagé :

    • Article : élément d'entité unique (détails d'un seul film)
    • collection : collection de projets (collection de tous les films)

    Chaque magasin aura les mêmes opérations CRUD, seule l'URL change

    Créer un plugin :

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

    Fournir des plugins pour Pinia :

    const pinia = createPinia();
    
    pinia.use(BaseStorePlugin);

    Exemple movieStore.js (utilisant des actions et un état partagés)

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

    Exemples d'utilisation dans les composants

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

    Editeur : 1

    Si vous transmettez le contexte dans le plugin, vous pouvez accéder au magasin et aux options qui y sont transmises, à partir desquelles vous pouvez vérifier l'ID du magasin et renvoyer uniquement le magasin spécifique comme indiqué ci-dessous

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

    J'ai créé un exemple très basique utilisant 3 magasins, le chèque ci-dessus est disponible dans codesandbox ici< /a>

    répondre
    0
  • Annulerrépondre