963 markdown files reformatted with the repository's pinned prettier so pnpm format:check covers the folded tree like every other repo file. The formatter's embedded-language pass also normalized code fences (TS semicolons, closed HTML tags in examples, lowercased CSS hex colors, one renumbered list that skipped an index). Alphanumeric token deltas vs the fold commit were audited file-by-file; all are formatter-equivalent markup normalizations plus the four sanitized skills.
3.6 KiB
3.6 KiB
name, description
| name | description |
|---|---|
| plugins | Extend stores with custom properties, methods, and behavior |
Plugins
Plugins extend all stores with custom properties, methods, or behavior.
Basic Plugin
import { createPinia } from 'pinia';
function SecretPiniaPlugin() {
return { secret: 'the cake is a lie' };
}
const pinia = createPinia();
pinia.use(SecretPiniaPlugin);
// In any store
const store = useStore();
store.secret; // 'the cake is a lie'
Plugin Context
Plugins receive a context object:
import { PiniaPluginContext } from 'pinia';
export function myPiniaPlugin(context: PiniaPluginContext) {
context.pinia; // pinia instance
context.app; // Vue app instance
context.store; // store being augmented
context.options; // store definition options
}
Adding Properties
Return an object to add properties (tracked in devtools):
pinia.use(() => ({ hello: 'world' }));
Or set directly on store:
pinia.use(({ store }) => {
store.hello = 'world';
// For devtools visibility in dev mode
if (process.env.NODE_ENV === 'development') {
store._customProperties.add('hello');
}
});
Adding State
Add to both store and store.$state for SSR/devtools:
import { toRef, ref } from 'vue';
pinia.use(({ store }) => {
if (!store.$state.hasOwnProperty('hasError')) {
const hasError = ref(false);
store.$state.hasError = hasError;
}
store.hasError = toRef(store.$state, 'hasError');
});
Adding External Properties
Wrap non-reactive objects with markRaw():
import { markRaw } from 'vue';
import { router } from './router';
pinia.use(({ store }) => {
store.router = markRaw(router);
});
Custom Store Options
Define custom options consumed by plugins:
// Store definition
defineStore('search', {
actions: {
searchContacts() {
/* ... */
},
},
debounce: {
searchContacts: 300,
},
});
// Plugin reads custom option
import debounce from 'lodash/debounce';
pinia.use(({ options, store }) => {
if (options.debounce) {
return Object.keys(options.debounce).reduce((acc, action) => {
acc[action] = debounce(store[action], options.debounce[action]);
return acc;
}, {});
}
});
For Setup Stores, pass options as third argument:
defineStore(
'search',
() => {
/* ... */
},
{
debounce: { searchContacts: 300 },
},
);
TypeScript Augmentation
Custom Properties
import 'pinia';
import type { Router } from 'vue-router';
declare module 'pinia' {
export interface PiniaCustomProperties {
router: Router;
hello: string;
}
}
Custom State
declare module 'pinia' {
export interface PiniaCustomStateProperties<S> {
hasError: boolean;
}
}
Custom Options
declare module 'pinia' {
export interface DefineStoreOptionsBase<S, Store> {
debounce?: Partial<Record<keyof StoreActions<Store>, number>>;
}
}
Subscribe in Plugins
pinia.use(({ store }) => {
store.$subscribe(() => {
// React to state changes
});
store.$onAction(() => {
// React to actions
});
});
Nuxt Plugin
Create a Nuxt plugin to add Pinia plugins:
// plugins/myPiniaPlugin.ts
import { PiniaPluginContext } from 'pinia';
function MyPiniaPlugin({ store }: PiniaPluginContext) {
store.$subscribe((mutation) => {
console.log(`[🍍 ${mutation.storeId}]: ${mutation.type}`);
});
return { creationTime: new Date() };
}
export default defineNuxtPlugin(({ $pinia }) => {
$pinia.use(MyPiniaPlugin);
});