Skip welcome & menu and move to editor
Welcome to JS Bin
Load cached copy from
 
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>React Hello World w/ JSBin</title>
</head>
<body>
  <div id="root"></div>
</body>
</html>
 
/** @jsx createElement */
function createElement(type, config, ...args) {
    const props = Object.assign({}, config);
    const hasChildren = args.length > 0;
    const rawChildren = hasChildren ? [].concat(...args) : [];
    props.children = rawChildren
        .filter(c => c != null && c !== false)
        .map(c => c instanceof Object ? c : createTextElement(c));
    // 过滤-空-值, 剩下的-不属于-Object的值 -> createTextElement -> 变为 类型为TEXT_ELEMENT- Didact元素
    return { type, props };
}
function createTextElement(value) {
    // 规范数据
    return createElement("TEXT ELEMENT", { nodeValue: value });
}
let rootInstance = null;
function render(element, container) {
    const prevInstance = rootInstance; //虚拟DOM的根节点
    const nextInstance = reconcile(container, prevInstance, element); //对比DOM diff,并更新真实DOM
    rootInstance = nextInstance; // 新的虚拟DOM根节点
}
function reconcile(parentDom, instance, element) {
    if (instance == null) {
        //虚拟的根节点为空时,使用当前React元素,创建新的虚拟DOM
        const newInstance = instantiate(element);
        //将真实DOM插入容器
        parentDom.appendChild(newInstance.dom);
        return newInstance;
    } else if (element == null) {
        //删除DOM
        parentDom.removeChild(instance.dom);
        return null;
    } if (instance.element.type === element.type) {
        //原有虚拟DOM节点类型与要创建的DOM节点类型一致时,可以重用dom以提升性能,只需要更新dom节点属性
        updateDomProperties(instance.dom, instance.element.props, element.props);
        //对instance子节点进行对比,以保证尽可能的重用DOM
        instance.childInstances = reconcileChildren(instance, element);
        instance.element = element;
        return instance;
    } else {
        //使用当前React元素,创建新的虚拟DOM
        const newInstance = instantiate(element);
        //将真实DOM替换容器中的原有DOM
        parentDom.replaceChild(newInstance.dom, instance.dom);
        return newInstance;
    }
}
function reconcileChildren(instance, element) {
    // instance 旧
    // element 新
    const dom = instance.dom;
    const childInstances = instance.childInstances;
    const nextChildElements = element.props.children || [];
    const newChildInstances = []; // 新的孩子数组
    //选取新旧子节点数据组中最大的值
    const count = Math.max(childInstances.length, nextChildElements.length);
    for (let i = 0; i < count; i++) {
        const childInstance = childInstances[i];
        const childElement = nextChildElements[i];
        //调用reconcile创建子节点的虚拟DOM
        /*这里存在三种情况:
         * (1). childInstance和childElement都存在,则调用reconcile进行diff操作
         * (2). childInstance为空而childElement存在,调用调用reconcile创建新的instance
         * (3). childInstance存在而childElement为空,则调用reconcile进行删除操作,此时会返回null
         */
        const newChildInstance = reconcile(dom, childInstance, childElement);
        newChildInstances.push(newChildInstance);
    }
    return newChildInstances.filter(instance => instance != null); //过滤null
}
function instantiate(element) {
    const { type, props } = element;
    const isTextElement = type === "TEXT ELEMENT";
    const dom = isTextElement
        ? document.createTextNode("")
        : document.createElement(type);
    updateDomProperties(dom, [], props); //更新DOM节点的属性、绑定事件
    //递归地调用instantiate函数,创建虚拟DOM的子节点
    const childElements = props.children || [];
    const childInstances = childElements.map(instantiate);
    const childDoms = childInstances.map(childInstance => childInstance.dom);
    childDoms.forEach(childDom => dom.appendChild(childDom));
    const instance = { dom, element, childInstances };
    return instance;
}
function updateDomProperties(dom, prevProps, nextProps) {
    //判断是否为事件属性
    const isEvent = name => name.startsWith("on");
    //判断是否为普通属性
    const isAttribute = name => !isEvent(name) && name != "children";
    //移除原有DOM节点上绑定的事件
    Object.keys(prevProps).filter(isEvent).forEach(name => {
        const eventType = name.toLowerCase().substring(2);
        dom.removeEventListener(eventType, prevProps[name]);
    });
    //移除原有DOM节点的普通属性
    Object.keys(prevProps).filter(isAttribute).forEach(name => {
        dom[name] = null;
    });
    //添加新属性
    Object.keys(nextProps).filter(isAttribute).forEach(name => {
        dom[name] = nextProps[name];
    });
    //添加新事件
    Object.keys(nextProps).filter(isEvent).forEach(name => {
        const eventType = name.toLowerCase().substring(2);
        dom.addEventListener(eventType, nextProps[name]);
    });
}
const list = [1, 1, 1]
function getElement() {
    return (
        <div id="container">
            <a style="width: 40; height: 20; background-color: #FF0000" onClick={handleClick} >click</a>
            {
                list.map(item => {
                    return <div>{item}</div>
                })
            }
        </div>
    );
}
function handleClick() {
    list.push(1)
    render(getElement(), document.getElementById("root"));
}
render(getElement(), document.getElementById("root"));
Output 300px

You can jump to the latest bin by adding /latest to your URL

Dismiss x
public
Bin info
anonymouspro
0viewers