Home > Net >  Inheritance / shared action and getters in Pinia
Inheritance / shared action and getters in Pinia

Time:11-08

I have a couple of Pinia stores that should share a set of actions and getters and I’m not quite sure how to effectively achieve that.

I’m building an app that lets users manage a number of different media (Books, Movies, TV Shows, etc). The way I’m currently thinking about it is to have a store for each media type e.g. BookStore, MovieStore etc. A lot of the getters and actions (e.g., count and deleteOne) are exactly the same between those different stores.

How do I achieve DRY here? The Pinia documentation has examples that mostly focus around reusing actions and getters inside other stores but I don’t think that quite solves my use case of inheriting a set of getters and setters outright.

Is my attempted inheritance approach here an anti-pattern?

CodePudding user response:

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: get single item from API and set response as item (https://url.com/movies/id)
  • handleError: displays alert to the user with error information

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

Give plugin to Pinia:

const pinia = createPinia();

pinia.use(BaseStorePlugin);

Example movieStore.js (using shared action & state)

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

Example usage in component

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