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>
Edit: 1
if you pass the context into the plugin you have access to the store and options being passed into it, from this you could check the store id and only return for specific stores like below
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}`
});
});
},
};
};
}
I have created a very basic example using 3 stores and the above check available on codesandbox here
this
inside them in TS. – Concentration