React & Didact
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
*/
React & Didact的更多相关文章
- Build your own React
		
Build your own React https://pomb.us/build-your-own-react/ https://github.com/pomber/didact demo htt ...
 - react组件的生命周期
		
写在前面: 阅读了多遍文章之后,自己总结了一个.一遍加强记忆,和日后回顾. 一.实例化(初始化) var Button = React.createClass({ getInitialState: f ...
 - 十分钟介绍mobx与react
		
原文地址:https://mobxjs.github.io/mobx/getting-started.html 写在前面:本人英语水平有限,主要是写给自己看的,若有哪位同学看到了有问题的地方,请为我指 ...
 - RxJS + Redux + React = Amazing!(译一)
		
今天,我将Youtube上的<RxJS + Redux + React = Amazing!>翻译(+机译)了下来,以供国内的同学学习,英文听力好的同学可以直接看原版视频: https:/ ...
 - React 入门教程
		
React 起源于Facebook内部项目,是一个用来构建用户界面的 javascript 库,相当于MVC架构中的V层框架,与市面上其他框架不同的是,React 把每一个组件当成了一个状态机,组件内 ...
 - 通往全栈工程师的捷径 —— react
		
腾讯Bugly特约作者: 左明 首先,我们来看看 React 在世界范围的热度趋势,下图是关键词“房价”和 “React” 在 Google Trends 上的搜索量对比,蓝色的是 React,红色的 ...
 - 2017-1-5 天气雨 React 学习笔记
		
官方example 中basic-click-counter <script type="text/babel"> var Counter = React.create ...
 - RxJS + Redux + React = Amazing!(译二)
		
今天,我将Youtube上的<RxJS + Redux + React = Amazing!>的后半部分翻译(+机译)了下来,以供国内的同学学习,英文听力好的同学可以直接看原版视频: ht ...
 - React在开发中的常用结构以及功能详解
		
一.React什么算法,什么虚拟DOM,什么核心内容网上一大堆,请自行google. 但是能把算法说清楚,虚拟DOM说清楚的聊聊无几.对开发又没卵用,还不如来点干货看看咋用. 二.结构如下: impo ...
 
随机推荐
- v-modal的使用。
			
v-model用于表单数据的双向绑定,其实它就是一个语法糖,这个背后就做了两个操作:v-bind绑定一个value属性:v-on指令给当前元素绑定input事件.
 - Shell 简单入门教程
			
大数据开发岗为什么要学习Shell呢?1)需要看懂大数据运维岗人员编写的Shell程序.2)偶尔会编写一些简单Shell程序来管理集群.提高开发效率 艺多不压身 Shell是一个命令行解释器,它接受应 ...
 - Spring Boot 系列总结
			
Spring Boot 系列总结 1.SpringBoot自动装配 1.1 Spring装配方式 1.2 Spring @Enable 模块驱动 1.3 Spring 条件装配 2.自动装配正文 2. ...
 - Stream API处理集合
			
使用流来遍历集合 简介 如何工作 总结 从集合或数组创建流 简介 如何工作 结论 聚合流的值 简介 如何工作 结论 转载 使用流来遍历集合 简介: Java的集合框架,如List和Map接口及Arra ...
 - Java性能优化,操作系统内核性能调优,JYM优化,Tomcat调优
			
文章目录 Java性能优化 尽量在合适的场合使用单例 尽量避免随意使用静态变量 尽量避免过多过常地创建Java对象 尽量使用final修饰符 尽量使用局部变量 尽量处理好包装类型和基本类型两者的使用场 ...
 - 配合 jekins—springboot脚本
			
#!/usr/bin/bash # author : renguangyin@yingu.com current=$(cd `dirname $0`; pwd) cd ${current} ext_n ...
 - 网际互连__OSI七层模型
			
概述 OSI(Open System Interconnection,开放系统互连)七层网络模型称为开放式系统互联参考模型 ,是一个逻辑上的定义.一个规范.它把网络从逻辑上分为了7层.每一层都有相关. ...
 - TypeScript中 typeof ArrayInstance[number] 剖析
			
假设这样一个场景,目前业务上仅对接了三方支付 'Alipay', 'Wxpay', 'PayPal', 实际业务 getPaymentMode 会根据不同支付方式进行不同的付款/结算流程. const ...
 - Pytest(1)安装与入门
			
pytest介绍 pytest是python的一种单元测试框架,与python自带的unittest测试框架类似,但是比unittest框架使用起来更简洁,效率更高.根据pytest的官方网站介绍,它 ...
 - CF Hello2020 D. New Year and Conference
			
D. New Year and Conference 题意 有\(2n\)个区间,分别为\([sa_1,ea_1],[sb_1,eb_1],[sa_2,ea_2],[sb_2,eb_2],\cdots ...