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的更多相关文章

  1. Build your own React

    Build your own React https://pomb.us/build-your-own-react/ https://github.com/pomber/didact demo htt ...

  2. react组件的生命周期

    写在前面: 阅读了多遍文章之后,自己总结了一个.一遍加强记忆,和日后回顾. 一.实例化(初始化) var Button = React.createClass({ getInitialState: f ...

  3. 十分钟介绍mobx与react

    原文地址:https://mobxjs.github.io/mobx/getting-started.html 写在前面:本人英语水平有限,主要是写给自己看的,若有哪位同学看到了有问题的地方,请为我指 ...

  4. RxJS + Redux + React = Amazing!(译一)

    今天,我将Youtube上的<RxJS + Redux + React = Amazing!>翻译(+机译)了下来,以供国内的同学学习,英文听力好的同学可以直接看原版视频: https:/ ...

  5. React 入门教程

    React 起源于Facebook内部项目,是一个用来构建用户界面的 javascript 库,相当于MVC架构中的V层框架,与市面上其他框架不同的是,React 把每一个组件当成了一个状态机,组件内 ...

  6. 通往全栈工程师的捷径 —— react

    腾讯Bugly特约作者: 左明 首先,我们来看看 React 在世界范围的热度趋势,下图是关键词“房价”和 “React” 在 Google Trends 上的搜索量对比,蓝色的是 React,红色的 ...

  7. 2017-1-5 天气雨 React 学习笔记

    官方example 中basic-click-counter <script type="text/babel"> var Counter = React.create ...

  8. RxJS + Redux + React = Amazing!(译二)

    今天,我将Youtube上的<RxJS + Redux + React = Amazing!>的后半部分翻译(+机译)了下来,以供国内的同学学习,英文听力好的同学可以直接看原版视频: ht ...

  9. React在开发中的常用结构以及功能详解

    一.React什么算法,什么虚拟DOM,什么核心内容网上一大堆,请自行google. 但是能把算法说清楚,虚拟DOM说清楚的聊聊无几.对开发又没卵用,还不如来点干货看看咋用. 二.结构如下: impo ...

随机推荐

  1. The WebSocket Protocol 1000

    https://tools.ietf.org/html/rfc6455 https://tools.ietf.org/html/rfc6455 7.4.1. Defined Status Codes ...

  2. Cognos软件介绍文档(原创)

    1. Cognos简介 Cognos是世界上最大的业务智能软件制造商,它能够帮助用户提取公司数据,然后分析并汇总得出报告.Cognos有许多产品,但最为著名的还是它的PowerPlay联机分析处理(o ...

  3. 【rz】【sz】参数详解

    参数 SYNOPSIS sz [-+8abdefkLlNnopqTtuvyY] file ... b:以二进制方式,默认为文本方式 e:对所有控制字符转义 待续 常见问题: 1.xshell 使用rz ...

  4. NOI Linux 快速入门指南

    目录 关于安装 NOI Linux 系统配置 网络 输入法 编辑器 1. gedit 打开 配置 外观展示 2. vim 打开 配置 使用 makefile 编译运行 1. 编写 makefile 2 ...

  5. 四:SpringBoot-定时任务和异步任务的使用方式

    SpringBoot-定时任务和异步任务的使用方式 1.定时任务 2.同步和异步 3.定时器的使用 3.1 定时器执行规则注解 3.2 定义时间打印定时器 3.3 启动类开启定时器注解 4.异步任务 ...

  6. 通达OA<=11.5版本SQL注入——日程安排

    注入点产生位置

  7. Mac变卡顿,优化性能

    当调整窗口大小,同时按住"Option"键,可以从中央调整大小 同时按住"Shift"键时,可以按比例调整大小.同时按住这两个键,那么既成比例,又从中央调整大小 ...

  8. (转)pip和easy_install使用方式

    easy_install 跟 pip 都是 Python 的套件管理程式,有了它們,在使用 Python 開發程式的時候會帶來不少方便. easy_install 和 pip 有什麼不一樣?據 pip ...

  9. f5添加多个vlan的方法

    1.方法一 方法二: F5不更改配置,核心添加路由 ip route 10.160.101.0 255.255.255.0 10.160.100.10

  10. JAVA对象分析之偏向锁、轻量级锁、重量级锁升级过程

    在HotSpot虚拟机里,对象在堆内存中的存储布局可以划分为三个部分: 对象头(Header) 实例数据(Instance Data) 对齐填充(Padding). 对象头 HotSpot虚拟机(后面 ...