Plugins
Pinia supports extending functionality through plugins. Here are some things you can extend:
-
Add new properties to the store
-
Add new methods to the store
-
Wrap existing methods
-
Modify or even cancel actions
-
Implement side effects, such as local storage
-
Apply plugins only to specific stores
Plugins are added to a Pinia instance via pinia.use(). The simplest example is adding a static property to all stores by returning an object.
import { createPinia } from 'pinia-react'
// Each created store will have a property named `secret` added to it.
// After installing this plugin, the plugin can be saved in different files
function SecretPiniaPlugin() {
return { secret: 'the cake is a lie' }
}
const pinia = createPinia()
// Pass the plugin to Pinia
pinia.use(SecretPiniaPlugin)
// In another file
const store = useStore()
store.secret // 'the cake is a lie'
Introduction
A Pinia plugin is a function that can optionally return properties to be added to the store. It receives an optional parameter, which is the context.
export function myPiniaPlugin(context) {
context.pinia // The pinia created with `createPinia()`.
context.store // The store that the plugin wants to extend
context.options // The optional object that defines the store passed to `defineStore()`.
}
Then pass this function to pinia using pinia.use():
Extending the Store
You can add specific properties to each store directly by returning an object containing those properties in a plugin:
pinia.use(() => ({ hello: 'world' }))
You can also set the property directly on the store,
pinia.use(({ store }) => {
store.hello = 'world'
})
Adding New State
If you want to add new state properties to the store, you must add them in two places at the same time.
- On the store, so you can access it with store.myState.
- On store.$state, so you can access it through store.$state.myState
pinia.use(({ store }) => {
// eslint-disable-next-line no-prototype-builtins
if (!Object.hasOwn(store.$state, 'pluginN')) {
store.$state.pluginN = 20
}
store.pluginN = store.$state.pluginN
})
Resetting Plugin-Added State
By default, $reset() does not reset state added by plugins, but you can override it to reset the state you added:
pinia.use(({ store }) => {
// eslint-disable-next-line no-prototype-builtins
if (!Object.hasOwn(store.$state, 'pluginN')) {
store.$state.pluginN = 20
}
store.pluginN = store.$state.pluginN
// Ensure context (`this`) is set to the store
const originalReset = store.$reset.bind(store)
// Override its $reset function
return {
$reset() {
originalReset()
store.pluginN = false
},
}
})
Calling $subscribe
in Plugins
You can also use store.$subscribe and store.$onAction in plugins.
pinia.use(({ store }) => {
store.$subscribe(() => {
// respond to store changes
})
store.$onAction(() => {
// respond to store actions
})
})
TypeScript
All the above features have type support, so you never need to use any or @ts-ignore.
Annotating Plugin Types
A Pinia plugin can be type-annotated as follows:
import { PiniaPluginContext } from 'pinia-react'
export function myPiniaPlugin(context: PiniaPluginContext) {
// ...
}
Adding Types for New Store Properties
When adding new properties to the store, you should also extend the PiniaCustomProperties interface.
import 'pinia'
declare module 'pinia' {
export interface PiniaCustomProperties {
simpleNumber: number
}
}
Then, you can safely write and read it:
pinia.use(({ store }) => {
store.simpleNumber = Math.random()
})
Adding Types for New State
When adding new state properties (including to store and store.$state), you need to add types to PiniaCustomStateProperties. Unlike PiniaCustomProperties, it only receives the State generic:
import 'pinia'
declare module 'pinia' {
export interface PiniaCustomStateProperties<S> {
hello: string
}
}