Plugins
Pinia-React supports extending functionality through plugins. A plugin is a function that is applied to every store instance upon creation. You can:
- Add new properties or methods to stores.
- Augment existing methods like
$reset.
- Implement side effects, such as logging or local storage persistence.
Add a plugin to your Pinia instance by calling pinia.use() in your application's entry point.
import { createPinia } from 'pinia-react'
// A simple plugin that adds a static property to every store.
function CreatedAtPlugin() {
return { createdAt: new Date() }
}
const pinia = createPinia()
pinia.use(CreatedAtPlugin)
// In a component or another file...
// const store = useSomeStore()
// console.log(store.createdAt) // The date the store was created
Introduction
A Pinia plugin is a function that receives a context object and can optionally return an object of properties to add to the store.
The context object contains three properties:
id: The unique ID of the store (the first argument passed to defineStore).
store: The store instance the plugin is augmenting.
options: The options object that was passed to defineStore().
export function myPiniaPlugin(context) {
console.log(`Plugin applied to store: ${context.id}`)
// context.store
// context.options
}
Extending the Store
You can add properties to every store by returning them from a plugin. These are merged into the store instance.
pinia.use(() => ({ hello: 'world' }))
You can also add properties directly on the store object, which is useful for complex objects or functions that need access to the store itself.
pinia.use(({ store }) => {
store.customMethod = () => {
console.log(`Hello from ${store.$id}`)
}
})
Warning: Plugins should never directly modify store.$state (e.g., store.$state.newProp = ...). Doing so bypasses the reactivity system and will cause your UI to not update. All state modifications must go through actions or $patch.
Augmenting $reset
The built-in $reset() method only resets state defined in the state() function. If a plugin adds its own properties to the store, you may want $reset to handle them as well. The correct way to do this is by augmenting (or "wrapping") the original $reset method.
Here is a safe example of a plugin that adds an ephemeralCounter property and a method to increment it. It then augments $reset to also reset this counter.
function EphemeralCounterPlugin({ store }) {
// Add a new property directly to the store instance
store.ephemeralCounter = 0
// Augment the original $reset method
const originalReset = store.$reset.bind(store)
return {
// Add a new method
incrementEphemeral() {
store.ephemeralCounter++
},
// Return a new, augmented $reset function
$reset() {
// Call the original reset logic first
originalReset()
// Then, reset the plugin's own property
store.ephemeralCounter = 0
console.log('Ephemeral counter was also reset.')
},
}
}
pinia.use(EphemeralCounterPlugin)
Calling $subscribe in Plugins
You can use store.$subscribe within a plugin to react to state changes, for example, to implement local storage persistence.
pinia.use(({ store, id }) => {
// You might want to get existing data from localStorage on startup
const savedState = localStorage.getItem(id)
if (savedState) {
store.$patch((draft) => {
Object.assign(draft, JSON.parse(savedState))
})
}
// Subscribe to changes to save them back
store.$subscribe((state) => {
localStorage.setItem(id, JSON.stringify(state))
})
})
TypeScript
Typing a Plugin
You can type a plugin's context for better type safety and autocompletion.
import { PiniaPluginContext } from 'pinia-react'
export function myPiniaPlugin(context: PiniaPluginContext) {
// ...
}
Typing New Store Properties
When you add new properties to a store via a plugin, you must also declare them globally in the PiniaCustomProperties interface for TypeScript to recognize them.
import 'pinia-react'
// Make sure this file is treated as a module.
export {}
declare module 'pinia-react' {
export interface PiniaCustomProperties {
// Add your plugin's properties here
createdAt: Date;
ephemeralCounter: number;
incrementEphemeral: () => void;
}
}
Now you can access these properties on any store instance with full type support.