SoFunction
Updated on 2025-04-05

,Description of the difference between using provide/inject injection

, Use provide/inject injection to the difference

Provide/inject introduction

Provide/inject communication method belongs to grandfather-grandson communication, and it is still very different. No matter how deep the level is, the components that initiate the provide can be used as dependency providers for all their subordinate components.

inject is initialized before data/props, and provide is initialized after data/props. The purpose is to allow users to use the content injected in data/props. That is to say, in order for data/props to depend on inject, the initialization inject needs to be placed in front of the initialization data/props.

Provide and inject binding are not responsive, this is deliberate, but if a responsive object is passed in, then the property of its object is still responsive. **

usage

vue2, x uses the same usage as data, both are configured as a function that returns an object.

export default (){
data:(
    return {
     msg:"messgae"
     }
  ),
provide:( 
    return {
        msg:
     }
  )  
}
export default {
  inject: [ 'msg'],
  mounted () {
    ();
  }
}

usage

inject() can only be run in the setup() life cycle, it cannot be run in other cycles, nor in event cycles (that is, it cannot be placed in asynchronous functions. When it is executed inject, it is no longer in the setup life cycle).

In addition, this cannot be used in setup, because setup is executed before data, computed, and methods, so this cannot retrieve the variables in the component.

  • setTimeout, (), mouse event retrieval, etc. cannot be executed inject in the function
  • Provide and inject are not responsive, but due to the particularity of the reference type, their properties can still respond normally after the descendants get the data. Reference type data can be used directly after obtaining it. After the property value is updated, the descendants' components will also be updated. Since it is not truly responsive, the view will not be updated if it is used in the template.
  • After the basic data type is directly provided, no matter how much you modify it, it cannot be updated. The value you get from the descendants component is always the first time.
<script setup>
import { provide } from "vue"
provide("msg","zhangsan")
</script>
<script setup>
import { inject } from "vue"
let msg = inject('msg')
(msg)
</script>

Question: Do you have to define it as responsive data or reference type data so that the grandson component can receive the latest value of the grandfather component data in real time (not talking about view updates, but only whether it can receive updates)?

You can define the basic data type, but return it. As shown below:

let name = "zhangsan"
provide('msg',()=>{
   return 'name'
})
const message = inject("msg")
(message()) //zhsngan

For basic data types, you need to provide a function and return it to the descendants' components, so that the data obtained by the descendants' components will be new each time. However, since it is not responsive, the descendants component needs to re-execute the function obtained by inject every time to get the latest data.

Prohibit the grandchild component to modify the grandfather component value

You can use shallowRef and readonly to wrap the parameters that need to be passed.

  • shallowRef: Only responsive forms of basic data types are processed, and no responsive processes of objects are processed.
  • readonly: Receive a ref or reactive wrapper object and return a read-only responsive object.
 const user = ref('Zhang San')
 provide('user', readonly(user)) // readonly is to prevent the inject side from modifying data to affect the provider side

Dependency injection problem of vue

When a module has more than two layers of components, it is too troublesome to emit from the descendant component to call the methods of the ancestor component or pass the ancestor's data to the descendant component layer by layer. When it needs to be modified, it also needs to find the places that need to be modified layer by layer.

Provides a "dependency injection" method, in which two new instance options are used: provide and inject

The provide option allows us to specify the data/methods we want to provide to the descendant components.

Ancestor Components:

...
data() {
 return {
  msg: ‘I am origin component data'
 }
},
provide: function() {
 return {
  getData() {
   (‘hi,I come from origin component')
  }
 },
 msg: 
},
...

Inject can be used in any descendant component to accept data/methods we specified in our ancestors

Descendant components:

...
inject: [‘getData', ‘msg'],
created() {
 ()
},
methods: {
 init() {
  (),
  ()
 }
}
...

However, dependency injection still has negative effects. It couples components in your application with how they are currently organized, making refactoring more difficult.

The properties provided are non-responsive. This is for design considerations, because using them to create a centralized and scaled data is not good enough to do this with $root.

If the property you want to share is unique to your application, not universal, or if you want to update the provided data in your ancestor components, then this means you may need to switch to a real state management solution like Vuex

Summarize

The above is personal experience. I hope you can give you a reference and I hope you can support me more.