zoukankan      html  css  js  c++  java
  • xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!

    Build your own React

    https://pomb.us/build-your-own-react/

    https://github.com/pomber/didact

    demo

    https://codesandbox.io/s/didact-8-kvegz

    
    function createElement(type, props, ...children) {
      return {
        type,
        props: {
          ...props,
          children: children.map(child =>
            typeof child === "object" ? child : createTextElement(child)
          )
        }
      };
    }
    
    function createTextElement(text) {
      return {
        type: "TEXT_ELEMENT",
        props: {
          nodeValue: text,
          children: []
        }
      };
    }
    
    function createDom(fiber) {
      const dom =
        fiber.type == "TEXT_ELEMENT"
          ? document.createTextNode("")
          : document.createElement(fiber.type);
    
      updateDom(dom, {}, fiber.props);
    
      return dom;
    }
    
    const isEvent = key => key.startsWith("on");
    const isProperty = key => key !== "children" && !isEvent(key);
    const isNew = (prev, next) => key => prev[key] !== next[key];
    const isGone = (prev, next) => key => !(key in next);
    function updateDom(dom, prevProps, nextProps) {
      //Remove old or changed event listeners
      Object.keys(prevProps)
        .filter(isEvent)
        .filter(key => !(key in nextProps) || isNew(prevProps, nextProps)(key))
        .forEach(name => {
          const eventType = name.toLowerCase().substring(2);
          dom.removeEventListener(eventType, prevProps[name]);
        });
    
      // Remove old properties
      Object.keys(prevProps)
        .filter(isProperty)
        .filter(isGone(prevProps, nextProps))
        .forEach(name => {
          dom[name] = "";
        });
    
      // Set new or changed properties
      Object.keys(nextProps)
        .filter(isProperty)
        .filter(isNew(prevProps, nextProps))
        .forEach(name => {
          dom[name] = nextProps[name];
        });
    
      // Add event listeners
      Object.keys(nextProps)
        .filter(isEvent)
        .filter(isNew(prevProps, nextProps))
        .forEach(name => {
          const eventType = name.toLowerCase().substring(2);
          dom.addEventListener(eventType, nextProps[name]);
        });
    }
    
    function commitRoot() {
      deletions.forEach(commitWork);
      commitWork(wipRoot.child);
      currentRoot = wipRoot;
      wipRoot = null;
    }
    
    function commitWork(fiber) {
      if (!fiber) {
        return;
      }
    
      let domParentFiber = fiber.parent;
      while (!domParentFiber.dom) {
        domParentFiber = domParentFiber.parent;
      }
      const domParent = domParentFiber.dom;
    
      if (fiber.effectTag === "PLACEMENT" && fiber.dom != null) {
        domParent.appendChild(fiber.dom);
      } else if (fiber.effectTag === "UPDATE" && fiber.dom != null) {
        updateDom(fiber.dom, fiber.alternate.props, fiber.props);
      } else if (fiber.effectTag === "DELETION") {
        commitDeletion(fiber, domParent);
      }
    
      commitWork(fiber.child);
      commitWork(fiber.sibling);
    }
    
    function commitDeletion(fiber, domParent) {
      if (fiber.dom) {
        domParent.removeChild(fiber.dom);
      } else {
        commitDeletion(fiber.child, domParent);
      }
    }
    
    function render(element, container) {
      wipRoot = {
        dom: container,
        props: {
          children: [element]
        },
        alternate: currentRoot
      };
      deletions = [];
      nextUnitOfWork = wipRoot;
    }
    
    let nextUnitOfWork = null;
    let currentRoot = null;
    let wipRoot = null;
    let deletions = null;
    
    function workLoop(deadline) {
      let shouldYield = false;
      while (nextUnitOfWork && !shouldYield) {
        nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
        shouldYield = deadline.timeRemaining() < 1;
      }
    
      if (!nextUnitOfWork && wipRoot) {
        commitRoot();
      }
    
      requestIdleCallback(workLoop);
    }
    
    requestIdleCallback(workLoop);
    
    function performUnitOfWork(fiber) {
      const isFunctionComponent = fiber.type instanceof Function;
      if (isFunctionComponent) {
        updateFunctionComponent(fiber);
      } else {
        updateHostComponent(fiber);
      }
      if (fiber.child) {
        return fiber.child;
      }
      let nextFiber = fiber;
      while (nextFiber) {
        if (nextFiber.sibling) {
          return nextFiber.sibling;
        }
        nextFiber = nextFiber.parent;
      }
    }
    
    let wipFiber = null;
    let hookIndex = null;
    
    function updateFunctionComponent(fiber) {
      wipFiber = fiber;
      hookIndex = 0;
      wipFiber.hooks = [];
      const children = [fiber.type(fiber.props)];
      reconcileChildren(fiber, children);
    }
    
    function useState(initial) {
      const oldHook =
        wipFiber.alternate &&
        wipFiber.alternate.hooks &&
        wipFiber.alternate.hooks[hookIndex];
      const hook = {
        state: oldHook ? oldHook.state : initial,
        queue: []
      };
    
      const actions = oldHook ? oldHook.queue : [];
      actions.forEach(action => {
        hook.state = action(hook.state);
      });
    
      const setState = action => {
        hook.queue.push(action);
        wipRoot = {
          dom: currentRoot.dom,
          props: currentRoot.props,
          alternate: currentRoot
        };
        nextUnitOfWork = wipRoot;
        deletions = [];
      };
    
      wipFiber.hooks.push(hook);
      hookIndex++;
      return [hook.state, setState];
    }
    
    function updateHostComponent(fiber) {
      if (!fiber.dom) {
        fiber.dom = createDom(fiber);
      }
      reconcileChildren(fiber, fiber.props.children);
    }
    
    function reconcileChildren(wipFiber, elements) {
      let index = 0;
      let oldFiber = wipFiber.alternate && wipFiber.alternate.child;
      let prevSibling = null;
    
      while (index < elements.length || oldFiber != null) {
        const element = elements[index];
        let newFiber = null;
    
        const sameType = oldFiber && element && element.type == oldFiber.type;
    
        if (sameType) {
          newFiber = {
            type: oldFiber.type,
            props: element.props,
            dom: oldFiber.dom,
            parent: wipFiber,
            alternate: oldFiber,
            effectTag: "UPDATE"
          };
        }
        if (element && !sameType) {
          newFiber = {
            type: element.type,
            props: element.props,
            dom: null,
            parent: wipFiber,
            alternate: null,
            effectTag: "PLACEMENT"
          };
        }
        if (oldFiber && !sameType) {
          oldFiber.effectTag = "DELETION";
          deletions.push(oldFiber);
        }
    
        if (oldFiber) {
          oldFiber = oldFiber.sibling;
        }
    
        if (index === 0) {
          wipFiber.child = newFiber;
        } else if (element) {
          prevSibling.sibling = newFiber;
        }
    
        prevSibling = newFiber;
        index++;
      }
    }
    
    const Didact = {
      createElement,
      render,
      useState
    };
    
    /** @jsx Didact.createElement */
    function Counter() {
      const [state, setState] = Didact.useState(1);
      return (
        <h1 onClick={() => setState(c => c + 1)} style="user-select: none">
          Count: {state}
        </h1>
      );
    }
    const element = <Counter />;
    const container = document.getElementById("root");
    Didact.render(element, container);
    
    
    

    https://github.com/chinanf-boy/didact-explain#1-渲染dom元素


    Flag Counter

    ©xgqfrms 2012-2020

    www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!


  • 相关阅读:
    Python基础学习参考(四):条件与循环
    Python基础学习参考(三):内置函数
    Python基础学习参考(二):基本语法
    2011的最后一篇博文 写给我自己也写给你们
    前端开发面试题
    常用js操作:
    两个嵌套for循环执行顺序
    在寻找学习js的途中,又发现了好的东西!
    arcgis api for js初学
    解决为什么arcgis api for js的first map里不显示arcgis地图
  • 原文地址:https://www.cnblogs.com/xgqfrms/p/11901967.html
Copyright © 2011-2022 走看看