分析provide 和 inject
使用 provide/inject 做全局状态管理
Vue 不会对 provide 中的变量进行响应式处理。所以,要想 inject 接受的变量是响应式的,provide 提供的变量本身就需要是响应式的。
// 父组件
<template>
<div id="app">
Parent组件
<br />
<button type="button" @click="changeName">改变name</button>
<br />
Parent组件中 name的值: {{ name }}
<HelloWorld msg="Hello Vue in CodeSandbox!" />
</div>
</template>
<script>
import HelloWorld from "./components/HelloWorld";
export default {
name: "App",
components: {
HelloWorld,
},
data() {
return {
name: "kevin",
store: {
login: true
}
};
},
created() {
this.userInfo = "created";
},
provide() {
return {
getReaciveNameFromParent: () => this.name,
store: () => this.store,
};
},
methods: {
changeName(val) {
this.name = "New Kevin";
this.store.login = false
},
},
};
</script>Vuex 和 provide/inject 最大的区别在于,Vuex 中的全局状态的每次修改是可以追踪回溯的,而 provide/inject 中变量的修改是无法控制的,换句话说,你不知道是哪个组件修改了这个全局状态。
原理
还记得我们注册全局组件过程中所用到的Vue.extend方法吗。
extendOptions 就包含我们inject属性,看看mergeOptions函数:
我们看看这个函数 normalizeInject(child, vm)
很简单就是把inject:『parentValue』 挂在了子组件中的options。inject对象下 vm.$options.inject = {"parentValue": {"from": "parentValue"}} 我们在实例化子组件的时候要用到, 看看实例化子组件时对 inject 的处理。 在 _init 时会调用 这个函数
看看这个 resloveInject
从这个函数可以看到通过while循环,以及source = source.$parent 找到父组件中的_provided属性,拿到其值,也就拿到父组件提供的provide了。所以说孙组件可以拿到父组件中的数据。
接着是_provide属性
在父组件实例化时, 我们也调用了 mergeOptions 对父组件的 provide 属性进行了处理:
这个options 参数里面包含 provide 属性。 看看mergeOptions 函数对 provide 的处理.
vm.$options.provide 就是 mergedInstanceDataFn 函数。通过调用这个函数我们 _provided 就成为了 {"parentValue":"here is parent data"}。
最后更新于
这有帮助吗?