跳至主要內容

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;
	}
}