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元素



xgqfrms 2012-2020

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


Build your own React的更多相关文章

  1. [MST] Build Forms with React to Edit mobx-state-tree Models

    We will expand our UI, and give the user the possibility to edit his wishlist. We will use the earli ...

  2. Vue.js 2.0 和 React、Augular等其他框架的全方位对比

    引言 这个页面无疑是最难编写的,但也是非常重要的.或许你遇到了一些问题并且先前用其他的框架解决了.来这里的目的是看看Vue是否有更好的解决方案.那么你就来对了. 客观来说,作为核心团队成员,显然我们会 ...

  3. 构建通用的 React 和 Node 应用

    这是一篇非常优秀的 React 教程,这篇文章对 React 组件.React Router 以及 Node 做了很好的梳理.我是 9 月份读的该文章,当时跟着教程做了一遍,收获很大.但是由于时间原因 ...

  4. Vue.js 2.0 和 React、Augular

    Vue.js 2.0 和 React.Augular 引言 这个页面无疑是最难编写的,但也是非常重要的.或许你遇到了一些问题并且先前用其他的框架解决了.来这里的目的是看看Vue是否有更好的解决方案.那 ...

  5. iOS程序员的React Native开发工具集

    本文整理了React Native iOS开发过程中有用的工具.服务.测试.库以及网站等. 工具 你可以选择不同的开发环境:DECO.EXPO或者你可以使用Nuclide+Atom,目前我使用EXPO ...

  6. react脚手架搭建及配置

    npm install -g create-react-app 装完之后,生成一个新的项目,可以使用下面的命令: create-react-app my-app cd my-app/yarn star ...

  7. Vue.js vs React vs Angular 深度对比[转]

    这个页面无疑是最难编写的,但我们认为它也是非常重要的.或许你曾遇到了一些问题并且已经用其他的框架解决了.你来这里的目的是看看 Vue 是否有更好的解决方案.这也是我们在此想要回答的. 客观来说,作为核 ...

  8. 解决升级到Xcode10,react native项目运行报错问题

    今天刚升级到Xcode10,就遇到两个报错问题 错误一:Xcode 10: Build input file double-conversion cannot be found error: Buil ...

  9. 使用 webpack 搭建 React 项目

    简评:相信很多开发者在入门 react 的时候都是使用 create-react-app 或 react-slingshot 这些脚手架来快速创建应用,当有特殊需求,需要修改 eject 出来的 we ...

随机推荐

  1. 【转载】【GDB】GDB with Python

    作者:薛定谔的喵链接:https://zhuanlan.zhihu.com/p/152274203来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 你还在用GDB调试程序 ...

  2. 理解前端模块概念:CommonJs与ES6Module

    前言 现代前端开发每时每刻都和模块打交道.例如,在项目中引入一个插件,或者实现一个供全局使用组件的JS文件.这些都可以称为模块. 在设计程序结构时,不可能把所有代码都放在一起.更为友好的组织方式时按照 ...

  3. nginx 配置文件解读

    参考:链接 在微服务的体系之下,Nginx正在被越来越多的项目采用作为网关来使用,配合 Lua 做限流.熔断等控制 --源自 nginx Lua 脚本语言,用标准C语言编写并以源代码形式开放, 其设计 ...

  4. 硬核!八张图搞懂 Flink 端到端精准一次处理语义 Exactly-once(深入原理,建议收藏)

    Flink 在 Flink 中需要端到端精准一次处理的位置有三个: Source 端:数据从上一阶段进入到 Flink 时,需要保证消息精准一次消费. Flink 内部端:这个我们已经了解,利用 Ch ...

  5. (七)整合 Redis集群 ,实现消息队列场景

    整合 Redis集群 ,实现消息队列场景 1.Redis集群简介 1.1 RedisCluster概念 2.SpringBoot整合Redis集群 2.1 核心依赖 2.2 核心配置 2.3 参数渲染 ...

  6. Spring Boot,Spring Cloud,Eureka,Actuator,Spring Boot Admin,Stream,Hystrix

    Spring Boot,Spring Cloud,Eureka,Actuator,Spring Boot Admin,Stream,Hystrix 一.Spring Cloud 之 Eureka. 1 ...

  7. Hadoop伪分布式环境搭建+Ubuntu:16.04+hadoop-2.6.0

    Hello,大家好 !下面就让我带大家一起来搭建hadoop伪分布式的环境吧!不足的地方请大家多交流.谢谢大家的支持 准备环境: 1, ubuntu系统,(我在16.04测试通过.其他版本请自行测试, ...

  8. Calendar 日期判断 等于 。小于。大于

    public static void main(String[] args) throws Exception { String startTime = "2012-12-12 12:45: ...

  9. ubuntu14.04 ssh允许root用户远程登录

    vi /etc/ssh/sshd_config #注释掉 #PermitRootLogin without-password # Authentication: LoginGraceTime 120 ...

  10. AtCoder Beginner Contest 163

    比赛链接:https://atcoder.jp/contests/abc163/tasks A - Circle Pond 题意 由半径输出圆周长. 代码 #include <bits/stdc ...