Vue implements component communication through provide inject

  • 2021-08-10 06:32:27
  • OfStack

provide/inject is a new API after Vue. js version 2.2. 0:

provide: Object () = > Object//1 object or a function that returns 1 object. This object contains properties that can be injected into its descendants.

inject: Array < string > {[key: string]: string Symbol Object}//1 string array, or 1 object

Although the official documentation states that provide and inject mainly provide use cases for high-level plug-in/component libraries. It is not recommended to use directly in application code, but in plug-in/component libraries (such as iView, in fact many components of iView are in use). However, suggestions are suggestions. If you use them well, this API will be very useful.

This pair of options requires one use to allow one ancestor component to inject one dependency into all its descendants, no matter how deep the component is, and to remain in effect for as long as the upstream-downstream relationship is established.

Note: provide and inject bindings are not responsive. This is obviously not a design mistake, but a deliberate one.

Let's look at 1 to see its simplest usage:


// Ancestor component (parent component) 
<template>
  <div>
    <Pro></Pro>
  </div>
</template>
<script>
import Pro from '../components/provide.vue';
export default {
  data(){
    return{
    }
  },
   provide:{
    foo:'test'
  },
  components:{
    Pro,
  }
}
</script>
<style scoped>
</style>

// Descendant component (subordinate component) 
<template>
  <div>
    <p>{{foo}}</p>
  </div>
</template>
<script>
export default {
  data(){
    return {
    }
  },
  inject:['foo'],
}
</script>
<style scoped>
</style>

We set an provide: foo in the superior component with the value of test, and its function is to provide the variable foo to all its subordinate components. In the lower component, the foo variable provided from the higher component is injected through inject, so it can be accessed directly through this. foo in the lower component.

Again, the binding of provide and inject is not responsive, so in the above example, the foo of the superior component has changed, but the values of this. foo of the subordinate component will not change.

We will import app. vue as the root component in main. js, and we need to make a fuss about app. vue, which is the key to our realization of functions. We can understand it this way: app. vue is used as an outermost root component to store all required global data and state. Because all the components in the project (including routing), its parent component (or root component) is app. vue, we can expose the entire app. vue instance through provide. Then, all components can share their data, methods, and so on.


<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>
<script>
export default {
  provide () {
   return {
    app: this
   }
  }
 }
</script>

Above, we provided the whole instance of app. vue ` this ` to the outside world. Next, if any component (or route) injects app. vue through ` inject `, it can access data, computed and method of app. vue through this. app. xxx.

app. vue is the first component to be rendered in the whole project, and it will only be rendered once (even if the route is switched, app. vue will not be rendered again). Using this feature, it is very suitable for once global state data management. For example, we save the user's login information:


//app.vue Part of the code is omitted: 
<script>
export default {
  provide () {
   return {
    app: this
   }
  },
  data () {
   return {
    userInfo: null
   }
  },
  methods: {
   getUserInfo () {
    //  Through here  ajax  After obtaining user information, assign a value to  this.userInfo The following is the pseudo code 
    $.ajax('/user/info', (data) => {
     this.userInfo = data;
    });
   }
  },
  mounted () {
   this.getUserInfo();
  }
 }
</script>

In this way, any page or component can directly access the data of userInfo as long as it injects app through inject, such as:


<template>
 <div>
  {{ app.userInfo }}
 </div>
</template>
<script>
export default {
  inject: ['app']
 }
</script>

Isn't it very simple? In addition to using data directly, you can also call methods. For example, in a certain page, the personal data has been modified, and userInfo, which was obtained in app. vue from 1, is not up to date and needs to be retrieved again. You can use this:


// A page: 
 
<template>
 <div>
  {{ app.userInfo }}
 </div>
</template>
<script>
export default {
  inject: ['app'],
  methods: {
   changeUserInfo () {
    //  After modifying the user data here, notify  app.vue  Update, the following is pseudo code 
    $.ajax('/user/update', () => {
     //  Direct through  this.app  You can call  app.vue  The method in this.app.getUserInfo();
    })
   }
  }
 }
</script>

It's also very simple. Once you understand that ` this. app ` is a direct retrieval of the entire instance of ` app. vue `, you are handy to use. Think 1, configure complex Vuex all the functions, now can be through the ` provide/inject ` to achieve?

If you are concerned about the Vue. js documentation that says that provide/inject is not recommended for use directly in your application, it doesn't matter. Just use the familiar Vuex or Bus to manage your project. The pair of API we introduced mainly play a role in independent components.

As long as one component uses ` provide 'to provide data down, all its child components can be injected through ` inject', no matter how many generations have elapsed between them, and multiple data supplied from different parents can be injected. Note that once you inject some data, such as ` app ` in the above example, you can no longer declare ` app ` in this component because it is already owned by the parent.

Advanced skills:

If your project is complex enough or requires multi-person collaborative development, there will be so much code written in app. vue that the structure is complex and difficult to maintain. You can use a hybrid mixins of Vue. js to separate the different logic into different js files.

Let me briefly introduce what mixins is:

Blending in (mixin) provides a very flexible way to distribute reusable functionality in Vue components. 1 Blended object can contain any component options. When a component uses blended objects, all blended object options are "blended" into the component's own options. (Personal understanding of mixins is to define 1 part of common methods or calculation attributes, and then mix them into various components for use, which is convenient for management and modification)

For example, the above user information can be put into the mix:


// New File (user.js)
export default {
 data () {
  return {
   userInfo: null
  }
 },
 methods: {
  getUserInfo () {
   //  Through here  ajax  After obtaining user information, assign a value to  this.userInfo The following is the pseudo code 
   $.ajax('/user/info', (data) => {
    this.userInfo = data;
   });
  }
 },
 mounted () {
  this.getUserInfo();
 }
}

Then mix in app. vue:


<script>
 import mixins_user from'../mixins/user.js';
 export default {
  mixins: [mixins_user],
  data () {
   return {
   }
  }
 }
</script>

In this way, the logic related to user information can be maintained in user. js, or maintained by someone, and app. vue can be easily maintained.

For more information on blending, please refer to the official document: https://cn.vuejs.org/v2/guide/mixins.html


Related articles: