• xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!


    React & Didact

    A DIY guide to build your own React

    https://github.com/pomber/didact

    https://github.com/pomber/didact/blob/master/didact.js

    demo

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

    
    // import React from "react";
    // import ReactDOM from "react-dom";
    // import React, { Component } from 'react';
    // import { render } from "react-dom";
    
    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");
    // ReactDOM.render(element, container);
    Didact.render(element, container);
    
    /*
    
    Didact.render is deprecated since React 0.14.0, 
    use ReactDOM.render instead (react/no-deprecated)eslint
    
    */
    
    
    

  • 相关阅读:
    Object-c的类可以多重继承么?可以实现多个接口么?如何实现?
    对于TableViewCell重用机制的理解
    xcode快捷方式
    Mysql数据迁移——按分号split一列字段插入另一张表
    Android手机导出微信聊天记录
    Java性能分析工具之Jprofiler初体验
    Android adb端口被占用的解决办法
    mysql limit查询性能优化
    Delphi异或算法转换为java实现
    [python]用Python进行SQLite数据库操作
  • 原文地址:https://www.cnblogs.com/xgqfrms/p/12790547.html
Copyright © 2020-2023  润新知