This is the second day of my participation in the November Gwen Challenge. Check out the details: the last Gwen Challenge 2021
The plugin can do
- to
store
Add new properties - define
store
To add a new option - to
store
Add a new method - Existing methods of packaging
- Change or even cancel operations
- Implement local storage and other side effects
- onlyFor a particular
store
application
Nature of the plugin
Pinia’s plug-in is essentially a function whose return value is mixed into the Store
Case study:
Import {createPinia} from 'pinia' // Add a secret attribute to all stores function SecretPiniaPlugin() {return {secret: 'the cake is a lie' } } const pinia = createPinia() pinia.use(SecretPiniaPlugin)Copy the code
Const store = useStore() store. Secret // 'The cake is a lie'Copy the code
export interface Pinia { install: Exclude<Plugin['install'], undefined> state: Ref<Record<string, StateTree>> use(plugin: PiniaStorePlugin): Pinia App _testing? : boolean }Copy the code
use(plugin) { if (! localApp) { toBeInstalled.push(plugin) } else { _p.push(plugin) } return this }Copy the code
Looking at the type definition of the source code, we can see that Pinia uses the plug-in through use, which is stored in the _p array of the instance and returns this, the current instance.
The timing of plug-in use
function buildStoreToUse( partialStore: StoreWithState<Id, S, G, A>, descriptor: StateDescriptor<S>, $id: Id, getters: G = {} as G, actions: A = {} as A, options: DefineStoreOptions<Id, S, G, A> ) { ... _p. ForEach ((extender) => {if (__DEV__ &&is_client) {// @ts-expect-error: plugins pinia._p.forEach((extender) => {if (__DEV__ &&is_client) {// @ts-expect-error: conflict between A and ActionsTree const extensions = extender({ store, app: pinia._a, pinia, options }) Object.keys(extensions || {}).forEach((key) => store._customProperties.add(key) ) assign(store, Extensions)} else {// the result returned by the plugin is mixed on the store // @ts-expect-error: conflict between A and ActionsTree assign(store, extender({ store, app: pinia._a, pinia, options })) } }) return store }Copy the code
We can see the application of the plugin in the buildStoreToUse function, and buildStoreToUse happens to be the last step in useStore, where we can get all the properties of the store completely.
We see that the function loops through all the plug-ins for pinia._p, extender is the plug-in we use. The plugin runs at this point, passing the {store, app: pinia. _A, pinia, options} composition argument to our plugin, which is the context our plugin gets. In the end, the plugin’s results are mixed with object.assign.
That is, the plug-in application succeeds. At this point our store’s capacity is increasing.
export function myPiniaPlugin(context) {
context.pinia // the pinia created with `createPinia()`
context.app // the current app created with `createApp()` (Vue 3 only)
context.store // the store the plugin is augmenting
context.options // the options object defining the store passed to `defineStore()`
// ...
}
Copy the code
Simple case
We can add attributes to each store by simply returning their objects in the plug-in:
pinia.use(() => ({ hello: 'world' }))
Copy the code
You can also set properties directly on the Store
pinia.use(({ store }) => {
store.hello = 'world'
})
Copy the code
Any properties returned by the plug-in will be automatically tracked by DevTools, so in order for Hello to be visible in DevTools, make sure store._customProperties is added to dev mode only if you want to debug it in DevTools:
// from the example above
pinia.use(({ store }) => {
store.hello = 'world'
// make sure your bundler handle this. webpack and vite should do it by default
if (process.env.NODE_ENV === 'development') {
store._customProperties.add('secret')
}
})
Copy the code