Plugins
-
plugin
是一个函数, 其接收一个context
作为参数, 其返回值将会被添加到store
上.context
参数pinia
:createPinia()
返回的Pinia
实例app
:createApp()
返回的app
store
: 被插件作用的store
options
: 定义defineStore
时传入第三个参数
- 返回值
- 返回对象, 其中的属性将被添加到
store
. 或者返回void
- 返回对象, 其中的属性将被添加到
- 📕只有
pinia
实例被传给app
之后创建的store
才会被plugin
作用.
-
plugin
的简单使用-
创建
src/store/plugin/test.ts
-
import { PiniaPluginContext } from 'pinia' export default function (context: PiniaPluginContext) { console.log('context.pinia', context.pinia); console.log('context.app', context.app); console.log('context.store', context.store); console.log('context.options', context.options); return { secret: 'don\'t tell anyone!' } }
-
-
main.js
-
import { createPinia } from 'pinia' import myPiniaPlugin from './store/plugin/test' const app = createApp(App); const pinia = createPinia(); app.use(pinia); pinia.use(myPiniaPlugin);
-
-
看下面的截图, 只有
user
和counter
两个store
被插件作用了, 而且每个store
上都有plugin
返回的参数. -
当然可以通过
store.[属性]
的方式直接使用-
<h2>By Plugin: {{ user.secret }}</h2>
-
-
📕返回的参数每个
store
各自一份, 并不共享. 即如果你修改了store A
的secret
,store B
的secret
不会被影响.
-
-
给
store
添加参数- 可以直接通过
store.[属性]
的方式给store
添加参数, 但是官网建议尽量使用返回值的方式来从而被开发者工具跟踪-
📕这种方式同样每个
store
都有自己的数据, 互不影响. -
📕这种方式其实就是给
store
添加新的state
-
export default function (context: PiniaPluginContext) { context.store.hello = 'world'; return { secret: 'don\'t tell anyone!' } }
-
这样的方式开发者工具并不会侦测到属性的添加, 只有在控制台打印
store
时才可以看到 -
如果一定要在开发者工具中看到这个属性, 请保证
仅
在开发环境
下使用_customProperties
. 因为生产环境下会被移除-
context.store.hello = 'world'; if (process.env.NODE_ENV === 'development') { context.store._customProperties.add('hello'); }
-
-
- 可以直接通过
-
给
store
添加响应式参数- 📕另外, 如果定义属性时使用响应式数据, 那么每个
store
都会有自己的属性; - 由于
store
本身是reactive
, 其会自动解包内部的ref
或者reactive
, 因此在访问器内部响应式数据时不需要使用.value
-
context.store.good = ref('bye'); console.log('no unwrapping', context.store.good);
- 在组件中使用
-
<h2>By Plugin Reactive: {{ user.good }}</h2>
-
function updateRefGood() { user.good = 'hahaha' console.log('after changing user good ', count.good) }
-
- 📕另外, 如果定义属性时使用响应式数据, 那么每个
- 但是响应式数据定义在插件之外, 那么所有的
store
共享一个属性.- 同样的套路, 现在
plugin
中定义数据 -
const bad = ref('sad') export default function (context: PiniaPluginContext) { context.store.hello = 'world'; // each store has its own good context.store.good = ref('bye'); console.log('no unwrapping', context.store.good); // all store share the same bad context.store.bad = bad; return { secret: 'don\'t tell anyone!' } }
- 在组件中
-
<h2>By Plugin nonReactive: {{ user.bad }}</h2> <button @click="updateRefBad">updateRefBad</button>
-
function updateRefBad() { user.bad = 'happy'; console.log('after changing user bad ', count.bad) }
-
- 同样的套路, 现在
- 给
store
添加新的state
- 如果想给
store
添加新的state property
可以通过下面两种方式- 直接通过
store.[属性名]
- 通过
store.$state
这样才能在开发者工具中使用, 并且在SSR
过程中被序列化.
- 直接通过
- 下面看第二种
-
export default function({ store } : PiniaPluginContext) { if (!Object.prototype.hasOwnProperty(store.$state, 'hasError')) { const hasError = ref(false); store.$state.hasError = hasError; } store.hasError = toRef(store.$state, 'hasError'); }
1️⃣
首先, 为了正确处理SSR
, 需要确保不覆盖任何已存在的值. 因此先判断是否存在hasError
2️⃣
如果不存在, 那么使用ref
定义. 这样每个store
都会有自己独立的hasError
3️⃣
其次, 如果已经存在hasError
, 我们需要将hasError
从state
转移到store
, 这样既可以通过store.hasError
访问, 也可以通过store.$state.hasError
访问.
-
- 📕这种情况下, 最后不要在
return
时返回hasError
了. 因为返回值会被展示在开发者工具中的state
部分, 又定义又返回就会展示两次了. - 📕在
plugin
中的增加state
或修改state
, 都不触发任何的订阅, 因为这时store
并不活跃
- 如果想给
- 添加外部属性
- 如果要添加外部属性, 添加来自其他库的类的实例, 添加其他非响应式的数据, 我们应该使用
markRaw
包装一下再传递给pinia
. -
context.store.language = markRaw({ locale: 'zh-CN', });
- 如果要添加外部属性, 添加来自其他库的类的实例, 添加其他非响应式的数据, 我们应该使用
- 调用
$onAction
和$subscribe
-
context.store.$subscribe((mutation, state) => { // ... }); context.store.$onAction(() => { // ... });
-