加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

preact源码学习(4)

发布时间:2020-12-15 06:58:10 所属栏目:百科 来源:网络整理
导读:这节开始说回收机制。在这之前把组件的最后一点内容收尾。buildComponentFromVNode相当于updateComponent,但里面存在替换操作。在替换过程一堆销毁函数出现了。 recollectNodeTree unmountComponent removeChildren removeNode export function buildCompone

这节开始说回收机制。在这之前把组件的最后一点内容收尾。buildComponentFromVNode相当于updateComponent,但里面存在替换操作。在替换过程一堆销毁函数出现了。

  1. recollectNodeTree

  2. unmountComponent

  3. removeChildren

  4. removeNode

export function buildComponentFromVNode(dom,vnode,context,mountAll) {
     //取得附上真实DOM上的组件实例
    let c = dom && dom._component,originalComponent = c,oldDom = dom,//判定两个构造器是否相等
        isDirectOwner = c && dom._componentConstructor===vnode.nodeName,isOwner = isDirectOwner,//添加默认属性
        props = getNodeProps(vnode);
     //寻找与之同类型的组件实例
    while (c && !isOwner && (c=c._parentComponent)) {
        isOwner = c.constructor===vnode.nodeName;
    }
      //如果能找到这个实例,并且不是在ReactDOM.render过程中
    if (c && isOwner && (!mountAll || c._component)) {
        setComponentProps(c,props,ASYNC_RENDER,mountAll);
        dom = c.base;
    }
    else { 
    //移除旧的实例,创建新的实例
        if (originalComponent && !isDirectOwner) {
            unmountComponent(originalComponent);
            dom = oldDom = null;
        }

        c = createComponent(vnode.nodeName,context);
        if (dom && !c.nextBase) {
            c.nextBase = dom;
            oldDom = null;
        }
        setComponentProps(c,SYNC_RENDER,mountAll);
        dom = c.base;
         
        if (oldDom && dom!==oldDom) {
            oldDom._component = null;//GC
            recollectNodeTree(oldDom,false);
        }
    }

    return dom;
}

unmountComponent是一个递归处理子组件的过程

export function unmountComponent(component) {
    if (options.beforeUnmount) options.beforeUnmount(component);

    let base = component.base;
     //防止用户在componentWillUnmount里进行setState
    component._disable = true;

    if (component.componentWillUnmount) component.componentWillUnmount();

    component.base = null;

//处理高阶组件
    let inner = component._component;
    if (inner) {
        unmountComponent(inner);
    }
    else if (base) {
    //如果组件最后生成的是元素节点,并且它上面有ref属性
        if (base[ATTR_KEY] && base[ATTR_KEY].ref) base[ATTR_KEY].ref(null);

        component.nextBase = base;

        removeNode(base);
        collectComponent(component);//收集元素节点

        removeChildren(base);
    }
    //处理组件自身的ref,如<Tooltip ref={()=>{  console.log(1)}}>
    if (component.__ref) component.__ref(null);
}

removeNode是将节点从它的父节点中分离出来

export function removeNode(node) {
    let parentNode = node.parentNode;
    if (parentNode) parentNode.removeChild(node);
}

下面是removeChildren与recollectNodeTree,removeChildren其实是个二道贩子,只是负责遍历,真正做的事的是recollectNodeTree。

export function removeChildren(node) {
    node = node.lastChild;
    while (node) {
        let next = node.previousSibling;
        recollectNodeTree(node,true);
        node = next;
    }
}
//recollectNodeTree用于移除组件与执行元素节点的缓存数据
export function recollectNodeTree(node,unmountOnly) {
    let component = node._component;
    if (component) {
        // if node is owned by a Component,unmount that component (ends up recursing back here)
        unmountComponent(component);
    }
    else {
        // If the node's VNode had a ref function,invoke it with null here.
        // (this is part of the React spec,and smart for unsetting references)
        if (node[ATTR_KEY]!=null && node[ATTR_KEY].ref) node[ATTR_KEY].ref(null);

        if (unmountOnly===false || node[ATTR_KEY]==null) {
            removeNode(node);
        }

        removeChildren(node);
    }
}

至此,销毁部分已经讲完了,还剩下diffAttributes及其内部实现。这个没有什么好谈,都是巨简单,里面尽是if else。

总评,preact其实从它这样体量的代码,许多情况是兼顾不及的。唯一称道的是性能。为了达成这性能,它尽量使用异步与_disable来控制组件的更新。为了确保数据不会乱,它是根据页面的真实DOM上来提取现有的虚拟DOM树进行diff。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读