Build your own React
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的更多相关文章
- [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 ...
- Vue.js 2.0 和 React、Augular等其他框架的全方位对比
引言 这个页面无疑是最难编写的,但也是非常重要的.或许你遇到了一些问题并且先前用其他的框架解决了.来这里的目的是看看Vue是否有更好的解决方案.那么你就来对了. 客观来说,作为核心团队成员,显然我们会 ...
- 构建通用的 React 和 Node 应用
这是一篇非常优秀的 React 教程,这篇文章对 React 组件.React Router 以及 Node 做了很好的梳理.我是 9 月份读的该文章,当时跟着教程做了一遍,收获很大.但是由于时间原因 ...
- Vue.js 2.0 和 React、Augular
Vue.js 2.0 和 React.Augular 引言 这个页面无疑是最难编写的,但也是非常重要的.或许你遇到了一些问题并且先前用其他的框架解决了.来这里的目的是看看Vue是否有更好的解决方案.那 ...
- iOS程序员的React Native开发工具集
本文整理了React Native iOS开发过程中有用的工具.服务.测试.库以及网站等. 工具 你可以选择不同的开发环境:DECO.EXPO或者你可以使用Nuclide+Atom,目前我使用EXPO ...
- react脚手架搭建及配置
npm install -g create-react-app 装完之后,生成一个新的项目,可以使用下面的命令: create-react-app my-app cd my-app/yarn star ...
- Vue.js vs React vs Angular 深度对比[转]
这个页面无疑是最难编写的,但我们认为它也是非常重要的.或许你曾遇到了一些问题并且已经用其他的框架解决了.你来这里的目的是看看 Vue 是否有更好的解决方案.这也是我们在此想要回答的. 客观来说,作为核 ...
- 解决升级到Xcode10,react native项目运行报错问题
今天刚升级到Xcode10,就遇到两个报错问题 错误一:Xcode 10: Build input file double-conversion cannot be found error: Buil ...
- 使用 webpack 搭建 React 项目
简评:相信很多开发者在入门 react 的时候都是使用 create-react-app 或 react-slingshot 这些脚手架来快速创建应用,当有特殊需求,需要修改 eject 出来的 we ...
随机推荐
- LOJ10138
ZJOI 2008 树上的统计 一树上有 n 个节点,编号分别为 1 到 n,每个节点都有一个权值 w.我们将以下面的形式来要求你对这棵树完成一些操作: CHANGE u t :把节点 u 权值改为t ...
- k8s之集群管理
导读 经过前面k8s系列的文章,这一系列已经基本完成,现在就用几篇文章说一下日常的集群维护. 目录 更新资源对象的Label Namespace:集群环境共享与隔离 部署集群监控 部署Web UI管理 ...
- Linux 调整系统时间偏差
在使用Linux系统部署项目,有时会出现时间跟当前时间不一致的情况,这个时候需要做些调整: 1.首先删除之前设置的时区 rm -rf /etc/localtime 2.创建上海时区 ln -s /us ...
- typedef void (*sighandler_t)(int);
typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler); ---------- ...
- HPE 交换机基础配置
1.交换机命名 (config)# hostname POE-SW 2.vlan创建及端口划分 1)端口加入vlan,两种方式 (config)# vlan 2 (vlan-2)# untagged ...
- Flink-v1.12官方网站翻译-P010-Fault Tolerance via State Snapshots
通过状态快照进行容错 状态后台 Flink管理的键控状态是一种碎片化的.键/值存储,每项键控状态的工作副本都被保存在负责该键的任务管理员的本地某处.操作员的状态也被保存在需要它的机器的本地.Flink ...
- Eureka详解系列(三)--探索Eureka强大的配置体系
简介 通过前面的两篇博客,我们知道了:什么是 Eureka?为什么使用 Eureka?如何适用 Eureka?今天,我们开始来研究 Eureka 的源码,先从配置部分的源码开始看,其他部分后面再补充. ...
- Word 脚本 (自用)
打开开发工具 右击功能区->自定义功能区 勾选开发工具->确定 导入代码 开发工具选项卡->Visual Basic 右击Normal->插入->模块 粘贴代码-> ...
- Luogu U13059 某种密码
应该没什么用的题目链接 题目背景 关于某种密码有如下描述:某种密码的原文A是由N个数字组成,而密文B是一个长度为N的01数串,原文和密文的关联在于一个钥匙码KEY.若KEY=∑▒[Ai*Bi],则密文 ...
- 【poj 2891】Strange Way to Express Integers(数论--拓展欧几里德 求解同余方程组 模版题)
题意:Elina看一本刘汝佳的书(O_O*),里面介绍了一种奇怪的方法表示一个非负整数 m .也就是有 k 对 ( ai , ri ) 可以这样表示--m%ai=ri.问 m 的最小值. 解法:拓展欧 ...