如何解决Vue报错:无法正确使用provide和inject进行跨级组件通信

1. 问题描述

在Vue的开发过程中,有时需要在父组件中定义一些公共的数据或方法,子组件可以通过这些数据或方法来进行通信或共享一些资源。在Vue中有两种方式来实现组件之间的通信:props和$emit和$on或$refs、 provide和inject。本篇文章主要讲解通过provide和inject实现子组件跨级通信时可能出现的问题及解决方法。

2. provide和inject简介

provide和inject是Vue中提供的一种祖先组件向后代组件传递数据的方式,可以在主要应用程序的根组件中提供数据,然后在任何需要它们的后代组件中注入它们。在父组件中,我们使用provide来提供一些数据或者对象,子组件中使用inject来注入这些数据或对象。

provide和inject的具体使用方法如下:

// 父组件提供数据

provide(){

return{

message:'hello world'

}

}

// 子组件注入数据

inject:['message']

3. 问题分析

在使用provide和inject实现跨级组件通信时,可能会出现无法正确使用的问题,报错信息如下:

[Vue warn]: Injection "xxxx" not found

出现该报错原因是控制台中报错的provide已经与inject相关的变量不匹配,可能是由于子组件中的inject没有注入父组件中通过provide提供的对象;或者是属性名、变量名不匹配。

3.1 inject未正确引用provide提供的变量

这种问题很容易出现,这是因为当父组件中使用provide来提供数据,子组件中的inject引用的变量与父组件不匹配,将导致provide提供的数据无法正确获取,出现报错。

// 父组件提供数据

provide(){

return{

message:'hello world'

}

}

// 子组件引用provide提供的变量,变量名不匹配

inject:['msg']

解决方法:子组件中的inject所引用的变量名要与父组件中provide所提供的变量名匹配。

// 父组件提供数据

provide(){

return{

message:'hello world'

}

}

// 子组件引用provide提供的变量,变量名匹配

inject:['message']

3.2 provide提供的变量为null或undefined

如果provide提供的变量为null或undefined,那么在子组件中inject引用的变量中将会返回undefined,当调用该变量时就会出现转换错误。还有一个问题就是Vue跟踪依赖性的机制,如果先定义了子组件,那么父组件提供的数据会被子组件多次引用,导致页面会多次渲染。

Vue在渲染页面时,会将provide提供的所有变量都与inject引用的变量进行依赖追踪,这就意味着,即使其中的某个变量没有实际使用,也会将其渲染出来。

//父组件提供数据

provide(){

return{

message:null

}

}

//子组件中调用provide提供的变量

inject: ['message']

...

created(){

console.log(this.message.toUpperCase())

}

解决方法:在父组件中,尽量避免提供null或undefined的变量,如果必须提供,可以使用默认值来避免Vue的依赖追踪机制对应用程序的性能产生影响。

//父组件提供数据(使用空对象替换原来的null)

provide(){

return{

message:{}

}

}

//子组件中调用provide提供的变量

// 此处通过解构赋值,定义了一个默认值为空对象的message变量

inject: {message:{ default: () => ({}) }}

...

created(){

console.log(this.message.toUpperCase())

}

3.3 provide提供的变量不是响应式的

provide提供的变量组件是静态的,即不是响应式的,这意味着在注入它们的组件中不能自动重新渲染页面。

//父组件提供数据

provide(){

return{

temperature:30

}

}

//子组件中调用provide提供的变量

inject:['temperature']

...

created(){

console.log(this.temperature)

}

解决方法:可以通过将指定的数据或对象封装在响应式对象中,然后在provide中提供响应式对象来实现响应式。

// 将temperature放在响应式对象中

provide () {

return {

temperature: Vue.observable({ value: 30 })

}

}

// 子组件中获取temperature的值

inject:['temperature']

...

created(){

console.log(this.temperature.value)

}

4. 总结

在Vue中使用provide和inject进行跨级组件通信时,需要注意变量名、变量值的匹配,以及provide提供的变量不是响应式的问题。在使用provide和inject提供和注入变量时,需要尽量在provide提供响应式对象,以方便子组件中可以及时获取变量变化并重新渲染页面。