在 Vue.js
中,provide
和 inject
是一种用于跨层级组件通信的机制,允许父组件向深层嵌套的子组件传递数据,而不需要通过 props
逐层传递。
使用方式
- 基础数据
// Parent
export default {
provide: {
word: "word",
obj: {
name: 'Parent'
},
arr: [1, 2, 3],
}
}
// Children
export default {
inject: ['word', 'obj', 'arr'],
data() {
return {
word: this.word
}
}
}
当provide
导出的数据为非响应式数据时,我们可以直接使用provide:{...}
的对象形式来向子孙组件导出我们的数据,且这个数据在被修改后无法更新渲染视图。
- 响应式数据
// Parent
export default {
data() {
return {
word: "Parent",
obj: {
name: 'Parent'
},
arr: [1, 2, 3]
}
},
provide() {
return {
word: this.word,
obj: this.obj,
arr: this.arr
}
}
}
// Children
export default {
inject: ['word', 'obj', 'arr'],
data() {
return {
word: this.word,
...
}
}
}
当provide
导出的数据为响应式数据时,我们可以直接使用provide(){return{...}}
的函数形式来向子孙组件导出我们的数据。
此时我们会发现比较坑的一个点就是我明明导出的是响应式数据,为什么在数据更新后,子组件并没有同步渲染更新。
经过试验我们发现当导出响应式数据时可分为几种情况:
- 响应式数据为基本类型
当为基本类型时,无论怎么修改父组件的data
数据,子组件都不会更新。 - 响应式数据为对象
当为对象类型时,直接赋值运算修改父组件的data
数据,子组件不会更新,而修改对象属性,则子组件的视图会被更新。 - 响应式数据为数组
当为数组类型时,直接赋值运算修改父组件的data
数据,子组件不会更新,而在v3版本中通过push
等操作修改时,子组件会被更新。
export default {
data() {
return {
word: "Parent",
obj: {
name: 'Parent'
},
arr: [1, 2, 3]
}
},
provide() {
return {
word: this.word,
obj: this.obj,
arr: this.arr
}
},
mounted() {
setTimeout(() => {
// 子组件更新数据
this.obj.name = 'ParentProvide'
this.arr.push(4)
// 子组件不更新数据
this.obj = {
name: 'ParentProvide'
}
this.arr = [4, 5, 6]
}, 5000);
}
}
在组合式API中 通过ref
reactive
声明的响应式数据则可以通过一下方式进行更新子组件
const word = ref('Parent');
provide('word', word);
const obj = reactive({ name: 'Parent' });
provide('obj', obj);
const arr = ref([1, 2, 3]);
provide('arr', arr);
setTimeout(() => {
word.value = 'ParentProvide';
obj.name = 'ParentProvide';
arr.value = [1, 2, 3, 4];
}, 5000);
因为ref
声明基本类型的响应式数据时,将基本类型转化为响应式对象,所以在通过xx.value
修改时,子组件会更新视图。
reactive
声明的响应式数据,由于整个对象为响应式的,则通过修改属性值,也可以实现子组件的更新。