15. 依赖注入原理
15. 依赖注入原理
1.基本使用
const My = {
setup() {
const name = inject('name');
return { name };
},
render() {
return h('div', this.name);
}
};
const VueComponent = {
setup() {
const state = reactive({ name: 'mrs erxiao' });
provide('name', state.name);
setTimeout(() => {
state.name = 'erxiao';
}, 1000);
return () => h(My);
}
};
render(h(VueComponent), app);
在创建实例时会采用父组件的 provides 属性
我们需要先构建组件渲染的父子关系
const patch = (n1, n2, container, anchor = null, parentComponent = null) => {
switch (type) {
case Fragment: // 无用的标签
processFragment(n1, n2, container, parentComponent);
break;
default:
if (shapeFlag & ShapeFlags.ELEMENT) {
processElement(n1, n2, container, anchor, parentComponent);
} else if (shapeFlag & ShapeFlags.COMPONENT) {
processComponent(n1, n2, container, anchor, parentComponent);
}
}
};
const processComponent = (n1, n2, container, anchor, parentComponent) => {
if (n1 == null) {
// 组件挂载的时候传入父组件
mountComponent(n2, container, anchor, parentComponent);
} else {
// 组件更新靠的是props
updateComponent(n1, n2);
}
};
export function createComponentInstance(vnode, parent) {
const instance = {
// 组件的实例
data: null,
parent,
provides: parent ? parent.provides : Object.create(null) // 创建一个provides对象
// ... 创建实例的时候标记父组件是谁
};
return instance;
}
2.Provide
export function provide(key, value) {
if (!currentInstance) return;
const parentProvides =
currentInstance.parent && currentInstance.parent.provides;
let provides = currentInstance.provides; // 获取当前实例的provides属性
// 如果是同一个对象,就创建个新的,下次在调用provide不必重新创建
// provides('a', 1);
// provides('b', 2)
if (parentProvides === provides) {
provides = currentInstance.provides = Object.create(provides); // 创建一个新的provides来存储
}
provides[key] = value;
}
3.Inject
export function inject(key, defaultValue) {
if (!currentInstance) return;
const provides = currentInstance.parent.provides;
if (provides && key in provides) {
return provides[key];
} else if (arguments.length > 1) {
return defaultValue;
}
}