install
什么是Vuex? Vuex是Vue官方专门为Vue.js应用程序开发的状态管理模式+库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。而Vuex4专门用于适配Vue3。
如何使用?
js
import { createApp } from 'vue'
import { createStore } from 'vuex'
// 创建一个新的store实例
const store = createStore({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++
}
}
})
const app = createApp({})
// 将store实例作为插件安装
app.use(store)
app.use的源码
位于core/packages/runtime-core/src/apiCreateApp.ts文件
createAppContext中对use方法进行了定义
ts
export function createAppAPI<HostElement>(
render: RootRenderFunction<HostElement>,
hydrate?: RootHydrateFunction,
): CreateAppFunction<HostElement> {
return function createApp(rootComponent, rootProps = null) {
// ... do something
const installedPlugins = new WeakSet()
const app: App = (context.app = {
_uid: uid++,
_component: rootComponent as ConcreteComponent,
_props: rootProps,
_container: null,
_context: context,
_instance: null,
// ... do something
use(plugin: Plugin, ...options: any[]) {
if (installedPlugins.has(plugin)) {
__DEV__ && warn(`Plugin has already been applied to target app.`)
} else if (plugin && isFunction(plugin.install)) {
installedPlugins.add(plugin)
plugin.install(app, ...options)
} else if (isFunction(plugin)) {
installedPlugins.add(plugin)
plugin(app, ...options)
} else if (__DEV__) {
warn(
`A plugin must either be a function or an object with an "install" ` +
`function.`,
)
}
return app
},
})
// ... dosomething
return app
}
}
app.use方法接收两个参数,分别是plugin和options,options是一个数组,对于plugin的类型,vue进行了一系列定义。
- 类型 pluginInstallFunction 是一个泛型类型,表示一个函数。Options默认为一个数组类型,且判断传入的Options为数组后将其类型更改为unknow[],否则为unknow。
- 类型ObjectPlugin是一个泛型类型,表示一个对象,它有一个install属性,类型是
pluginInstallFunction<Options>
- 类型FunctionPlugin 。。。
ts
type PluginInstallFunction<Options = any[]> = Options extends unknown[]
? (app: App, ...options: Options) => any
: (app: App, options: Options) => any
export type ObjectPlugin<Options = any[]> = {
install: PluginInstallFunction<Options>
}
export type FunctionPlugin<Options = any[]> = PluginInstallFunction<Options> &
Partial<ObjectPlugin<Options>>
export type Plugin<Options = any[]> =
| FunctionPlugin<Options>
| ObjectPlugin<Options>
- use方法执行后会先进入一系列判断流程
- 首先判断当前插件是否重复注册,如果是则发出警告。
js
if (installedPlugins.has(plugin)) {
__DEV__ && warn(`Plugin has already been applied to target app.`)
}
- 其次判断当前插件中的install方法是否为函数,如果是则将当前插件添加到WeakSet中,并执行install方法。
js
else if (plugin && isFunction(plugin.install)) {
installedPlugins.add(plugin)
plugin.install(app, ...options)
}
- 其次判断plugin是否为函数,如果是则执行同上一步的流程(只不过执行的是plugin方法)
js
else if (isFunction(plugin)) {
installedPlugins.add(plugin)
plugin(app, ...options)
}
- 否则,警告一个插件必须是一个函数或者对象,并且拥有install方法。
js
else if (__DEV__) {
warn(
`A plugin must either be a function or an object with an "install" ` +
`function.`,
)
}
vuex中的install方法
位于/src/store.js文件
该文件主要定义了Store构造器。在Store构造器中存在install方法。
ts
install (app, injectKey) {
app.provide(injectKey || storeKey, this)
app.config.globalProperties.$store = this
const useDevtools = this._devtools !== undefined
? this._devtools
: __DEV__ || __VUE_PROD_DEVTOOLS__
if (useDevtools) {
addDevtools(app, this)
}
}
根据上面app.use源码我们可以得知,app.use方法依赖于库中的install方法。在vuex的方法中通过app.provide方法向vue应用全局注入store实例(默认key值为store);并通过app.config.globalProperties向vue全局挂载$store属性,用于获取当前Store实例。同时根据用户配置决定是否启用vue官方开发者工具。
app.provide源码
在上面install方法中使用了app.provide向应用注入store实例,那么app.provide方法又干了些什么呢?
位于 ./packages/runtime-core/src/apiInject.ts文件
ts
import { currentInstance } from './component'
export function provide<T, K = InjectionKey<T> | string | number>(
key: K,
value: K extends InjectionKey<infer V> ? V : T,
) {
if (!currentInstance) {
if (__DEV__) {
warn(`provide() can only be used inside setup().`)
}
} else {
let provides = currentInstance.provides
// by default an instance inherits its parent's provides object
// but when it needs to provide values of its own, it creates its
// own provides object using parent provides object as prototype.
// this way in `inject` we can simply look up injections from direct
// parent and let the prototype chain do the work.
const parentProvides =
currentInstance.parent && currentInstance.parent.provides
if (parentProvides === provides) {
provides = currentInstance.provides = Object.create(parentProvides)
}
// TS doesn't allow symbol as index type
provides[key as string] = value
}
}
- 获取当前组件实例上的provides
- 判断父组件是否存在provides
- 存在则赋值当前provides为父组件provides
- 保存新增的provides