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提供响应式对象,以方便子组件中可以及时获取变量变化并重新渲染页面。