分析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"}。

最后更新于

这有帮助吗?