手写 mini-vue3 实现 getCurrentInstance 、provide & inject(七)

42 阅读1分钟

getCurrentInstance

// runtime-core/component.ts
let currentInstance = null;
export function getCurrentInstance() {
  return currentInstance;
}

function setCurrentInstance(instance) {
  currentInstance = instance;
}

setup 调用之前设置

// runtime-core/component.ts
function setupStatefulComponent(instance) {
  const Component = instance.type;
  const { setup } = Component;
  
  // 实现组件对象的代理
  ...

  if(setup) {
    // 需要在 setup 调用之前设置
    setCurrentInstance(instance);
    const setupResult = setup(shallowReadonly(instance.props), {
      emit: instance.emit,
    });
    setCurrentInstance(null);
    
    // 处理 setup函数的返回结果
    ...
  }
}

实现 provide inject

provide inject 可以实现父子通信/跨层级通信,所以给组件实例添加一个 parent,表示父虚拟节点的实例。

// runtime-core/component.ts
export function createComponentInstance(vnode, parent) {
  const component = {
    provides: parent ? parent.provides : {},
    parent,
  };
  return component;
}

provide

// runtime-core/apiInject.ts
export function provide(key, value) {
  // 存
  const currentIsntance: any = getCurrentInstance();

  if(currentIsntance) {
    let { provides } = currentIsntance;
    const parentProvides = currentIsntance.parent.provides;

    // init
    if(provides === parentProvides) {
      // A = Object.create(B),把 B 作为 A 的原型,A.__proto__ = B
      // 这里让 currentInstance.provides 继承父实例的 provides,是为了不让父实例的 provides 被修改
      provides = currentIsntance.provides = Object.create(parentProvides);    
    }
    provides[key] = value;
  }
}

inject

// runtime-core/apiInject.ts
export function inject(key, defaultValue) {
  // 取
  const currentIsntance: any = getCurrentInstance();

  if(currentIsntance) {
    const parentProvides = currentIsntance.parent.provides;

    // 沿着 parentProvides 的原型链找,在父节点找到,便返回父节点的,
    // 父节点没有再往父节点的父节点上找,原型链原理
    if(key in parentProvides) {
      return parentProvides[key];
      
    } else if(defaultValue) {
      if(typeof defaultValue === 'function') {
        return defaultValue();
        
      } else {
        return defaultValue;
      }
    }
  }
}

补全函数的 parentComponent 参数

// runtime-core/renderer.ts
function render(vnode, container) {
    patch(vnode, container, null);
}

function patch(vnode, container, parentComponent) {}

function processComponent(vnode, container, parentComponent) {
    mountComponent(vnode, container, parentComponent);
}

function mountComponent(initialVNode, container, parentComponent) {
    // 创建组件实例 instance
    const instance = createComponentInstance(initialVNode, parentComponent);
}

function processFragment(vnode, container, parentComponent) {
    mountFragment(vnode, container, parentComponent);
}

function mountFragment(vnode, container, parentComponent) {
    mountChildren(vnode, container, parentComponent);
}

function processElement(vnode, container, parentComponent) {
    mountElement(vnode, container, parentComponent)
}

function mountElement(vnode, container, parentComponent) {}

function mountChildren(vnode, container, parentComponent) {
    vnode.children.forEach(v => {
        patch(v, conatiner, parentComponent);
    });
}

function setupRenderEffect(instance, initialVNode, container) {
    patch(ubTree, container, instance);
}

导出 API

// runtime-core/index.ts
export { getCurrentInstance } from './component';
export { provide, inject } from './apiInject';