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 ...
随机推荐
- HTTPS学习(二):原理与实践
div.example { background-color: rgba(229, 236, 243, 1); color: rgba(0, 0, 0, 1); padding: 0.5em; mar ...
- Java帝国的成立
java帝国的成立 一场旷日持久的战争 1972年C语言诞生 贴近硬件 ,运行极快 , 效率极低 操作系统, 编译器 ,数据库, 网络系统 指针和内存 (容易犯错 , 暴力) 1982 年C++诞生 ...
- AtCoder Beginner Contest 178
比赛链接:https://atcoder.jp/contests/abc178/tasks A - not 题意 给出一个整数 $0 \le x \le 1$,如果 $x$ 是 $0$ 就输出 $1$ ...
- HDU 3032 Nim or not Nim?(SG打表找规律)
题意: 给你n堆石子,你每次只能操作一堆石子 1.拿去任意个,最少1个 2.把这一堆分成两堆,没有要求对半分 解析+代码: 1 //解题思路: 2 //对于一个给定的有向无环图,定义关于图的每个顶点的 ...
- hdu2126 Buy the souvenirs
Problem Description When the winter holiday comes, a lot of people will have a trip. Generally, ther ...
- CF1466-C. Canine poetry
CF1466-C. Canine poetry 题意: 给出一个字符串,这个字符串里面可能会包含多个回文子字符串.现在你可以任意修改这个字符串中的任意一个字符任意次数,问你最少多少操作数之后这个字符串 ...
- markdown 公式编写及不同平台公式转换
1.markdown 用法及公式编写,这块就不再重复,已有很多官方平台的文档说明很完善 有道云markdown写作文档 在博客园中插入公式 markdown公式输入(特殊符号) markdown 特殊 ...
- VMware ESXi 开启嵌套虚拟化
VMware ESXi 默认不支持嵌套虚拟化功能,需要修改相关配置文件才能支持. 1.Esxi主机开启ssh,修改 /etc/vmware/config 配置文件,在配置文件后面加入如下配置:vhv. ...
- Linux-关于Bash
目录 关于Bash Bash是什么? Bash的一些特性 关于Bash Bash是什么? Bash是一个命令处理器,通常运行于文本窗口中,并能执行用户直接输入的命令. Bash还能从文件中读取命令,这 ...
- L3-015. 球队“食物链”【DFS + 剪枝】
L3-015. 球队"食物链" 时间限制 1000 ms 内存限制 262144 kB 代码长度限制 8000 B 判题程序 Standard 作者 李文新(北京大学) 某国的足球 ...