2.7 KiB
2.7 KiB
name, description
| name | description |
|---|---|
| composables-in-stores | Using Vue composables within Pinia stores |
Composables in Stores
Pinia stores can leverage Vue composables for reusable stateful logic.
Option Stores
Call composables inside the state property, but only those returning writable refs:
import { defineStore } from 'pinia';
import { useLocalStorage } from '@vueuse/core';
export const useAuthStore = defineStore('auth', {
state: () => ({
user: useLocalStorage('pinia/auth/login', 'bob'),
}),
});
Works: Composables returning ref():
useLocalStorageuseAsyncState
Doesn't work in Option Stores:
- Composables exposing functions
- Composables exposing readonly data
Setup Stores
More flexible - can use almost any composable:
import { defineStore } from 'pinia';
import { useMediaControls } from '@vueuse/core';
import { ref } from 'vue';
export const useVideoPlayer = defineStore('video', () => {
const videoElement = ref<HTMLVideoElement>();
const src = ref('/data/video.mp4');
const { playing, volume, currentTime, togglePictureInPicture } = useMediaControls(videoElement, {
src,
});
function loadVideo(element: HTMLVideoElement, newSrc: string) {
videoElement.value = element;
src.value = newSrc;
}
return {
src,
playing,
volume,
currentTime,
loadVideo,
togglePictureInPicture,
};
});
Note: Don't return non-serializable DOM refs like videoElement - they're internal implementation details.
SSR Considerations
Option Stores with hydrate()
Define a hydrate() function to handle client-side hydration:
import { defineStore } from 'pinia';
import { useLocalStorage } from '@vueuse/core';
export const useAuthStore = defineStore('auth', {
state: () => ({
user: useLocalStorage('pinia/auth/login', 'bob'),
}),
hydrate(state, initialState) {
// Ignore server state, read from browser
state.user = useLocalStorage('pinia/auth/login', 'bob');
},
});
Setup Stores with skipHydrate()
Mark state that shouldn't hydrate from server:
import { defineStore, skipHydrate } from 'pinia';
import { useEyeDropper, useLocalStorage } from '@vueuse/core';
export const useColorStore = defineStore('colors', () => {
const { isSupported, open, sRGBHex } = useEyeDropper();
const lastColor = useLocalStorage('lastColor', sRGBHex);
return {
// Skip hydration for client-only state
lastColor: skipHydrate(lastColor),
open, // Function - no hydration needed
isSupported, // Boolean - not reactive
};
});
skipHydrate() only applies to state properties (refs), not functions or non-reactive values.