What is the use of provide / inject for vue?

1. Preface

What does vue's parent-child component communicate with?
: a combination of prop and $emit.
What if it's a grandson component?
: The parent component is then used to forward data and events.
What about Grandpa and Grandpa components?
: of course vuex
emmm Okay, there's nothing for me. I'll go now.

No, I can still struggle a little longer!Certainly some brothers do relatively small projects, component communication is not very much, lazy to introduce vuex, then provide/inject is the best solution to the communication problem of Grandfather (not limited to Grandfather/son, how many levels can be separated)!

2. Introduction of copied official documents

This option needs to be used together to allow an ancestor component to inject a dependency into all its descendants, regardless of how deep the component hierarchy is, and will remain in effect for as long as the upstream and downstream relationship is established.

provide The option should be

  • An object or a function that returns an object.The object contains attributes that can be injected into its descendants.In this object you can use ES2015 Symbols As key,But only in native support Symbol and Reflect.ownKeys It works in an environment.

inject The options should be:

  • An array of strings, or
  • An object(Detail Click Here)

3.Basic Usage

// Ancestor component provides foo
//First
export default {
  name: "grandfather",
  provide(){
    return{
      foo:'halo'
    }
  },
}
//Second
export default {
  name: "grandfather",
  provide:{
    foo:'halo~~~~'
  },
}
//Descendant component injection foo
export default {
  inject:['foo'],
}

Are there any differences between the above two uses?

  • If you just pass in a string, like'halo'above, there is no difference and future generations can read it.
  • If you need to pass an object (code shown below), the second is not, and future components will not get the data.So only the first is recommended
//When you pass on objects to future generations
provide(){
    return{
      test:this.msg
    }
  },

Note: Once you inject some data, such as foo in the example above, you can no longer declare foo in this component because it is already owned by the parent.

4. When will it be responsive?

If you've used vuex, you'll think that in the example above, if I change foo:'halo'to foo:'world', the subcomponents respond to data changes in a timely manner and the view is updated.

Unfortunately, no

There is a sentence in the official vue document

Tip: provide and inject bindings are not responsive.This is intentional.However, if you pass in a listenable object, its properties are responsive.

Instead of discussing why vue is designed this way, I'll just show you when provide/inject can respond

provide(){
  return{
    test:this.msg
  }
},
data() {
  return {
    msg: "Welcome to Your Vue.js App",
  }
}
mounted(){
  setTimeout(()=>{
    this.msg = "halo world";
    console.log(this._provided.msg)
    //log: Welcome to Your Vue.js App
  },3000)
},

As shown above, this is not possible, the data in the printed provided is unchanged, and the values obtained by the subcomponents are unchanged.
You can even assign a value to this._provided.msg directly, but even if the value inside _provided.msg changes, the value of the subcomponent remains unchanged.

When you do this like the following, you can respond

provide(){
  return{
    test:this.activeData
  }
},
data() {
  return {
    activeData:{name:'halo'},
  }
}
mounted(){
  setTimeout(()=>{
    this.activeData.name = 'world';
  },3000)
}

This is the property of the object written in vue that can be responded to

However, if you pass in a listenable object, its properties are responsive.

5. Implement global variables

Global variable?Can't provide/inject only be passed from ancestor to descendant?Yes, we just need to bind to the top-most component.

It's you!app.vue
We throw an entire instance to future generations!

//app.vue
export default {
  name: 'App',
  provide(){
    return{
      app:this
    }
  },
  data(){
    return{
      text:"it's hard to tell the night time from the day"
    }
  },
  methods:{
    say(){
      console.log("Desperado, why don't you come to your senses?")
    }
  }
}
//All other subcomponents, which require global variables, need to be injected with app as needed
export default {
  inject:['foo','app'],
  mounted(){
    console.log(this.app.text);//Get variables in app
    this.app.say();//You can execute the method in app and become a global method!
  }
}

This is also respondable oh~

6. Implement page refresh

1. Reroute to current page with vue-router, page is not refreshed
2. When window.reload() or router.go(0) is refreshed, the whole browser reloads, flashes and the experience is not good.

So what do we do?

Similar to the above principle, we only write a function in the component that controls routing (use v-if to control the display hiding of router-view, which is not covered here), then pass this function to descendants, and then call this method in the descendant component to refresh the route.

//app.vue
<router-view v-if="isShowRouter"/>

export default {
  name: 'App',
  provide(){
    return{
      reload:this.reload
    }
  },
  data(){
    return{
      isShowRouter:true,
    }
  },
  methods:{
    reload(){
      this.isShowRouter = false;
      this.$nextTick(()=>{
        this.isShowRouter = true;
      })
    }
  }
}
//Descendant components
export default {
  inject:['reload'],  
}

7. End

Prompt in vue

Note: Provide and inject provide use cases mainly for high-level plug-ins/component libraries.Direct use in application code is not recommended.

provide/inject is used less often and most of it is used to develop components, but it is still useful in some cases.
Business is huge and complex, or vuex~

If there are any errors or suggestions in the article, please point them out in the comments section. Thank you very much~

Tags: Javascript Vue less

Posted on Sat, 09 Nov 2019 02:12:21 -0500 by kevinritt