diff --git a/docs/engineering/function.md b/docs/engineering/function.md index 37eeb3e..c511db3 100644 --- a/docs/engineering/function.md +++ b/docs/engineering/function.md @@ -1027,7 +1027,7 @@ console.log(a) //[1,2,3,4] ### 2.8.3 深拷贝实现 -#### :tomato: JSON.parse(JSON.string(obj)) +#### :tomato: JSON.parse(JSON.stringify(obj)) ```javascript let obj = { diff --git a/docs/jsadvanced/function.md b/docs/jsadvanced/function.md index e1bf5fe..4c56d09 100644 --- a/docs/jsadvanced/function.md +++ b/docs/jsadvanced/function.md @@ -1027,7 +1027,7 @@ console.log(a) //[1,2,3,4] ### 2.8.3 深拷贝实现 -#### :tomato: JSON.parse(JSON.string(obj)) +#### :tomato: JSON.parse(JSON.stringify(obj)) ```javascript let obj = { diff --git a/docs/sundry/react.md b/docs/sundry/react.md index 36d6564..db717cc 100644 --- a/docs/sundry/react.md +++ b/docs/sundry/react.md @@ -1,6 +1,6 @@ -## 【译】build-your-own-react +## 【译】build-your-own-react -### 背景 +

背景

我们将从头开始重写react,遵循真实的React代码架构,没有优化和非必要功能。 @@ -8,8 +8,10 @@ 你可以在 Didact 存储库中找到旧博客文章和代码的历史记录。还有一个演讲涵盖了相同的内容。但这是一个独立的帖子。 +

目录

+ * [Step0: Review(回顾)](#0) -* [Step1: The createElement Function(创建函数组件)](#1) +* [Step1: The createElement Function(createElement 函数)](#1) * [Step2: render Function](#2) * [Step3: Concurrent Mode (并行模式)](#3) * [Step4: Fibers](#4) @@ -18,8 +20,7 @@ * [Step7: Function Components 函数组件](#7) * [Step8: Hooks](#8) - -### Step1: Review(回顾) +

Step0: Review(回顾)

我们先回顾一些基本概念,如果你对React、JSX、DOM元素的工作原理比较了解,你可以跳过这一步。 @@ -56,18 +57,160 @@ const element = { }, } ``` -以上就是一个 React Element ,一个具有两个属性(type与props)的对象。(好吧,它还有更多,但我们只关心这两个)。 +以上就是一个React Element ,一个具有两个属性(type与props)的对象。(好吧,它还有更多,但我们只关心这两个)。 + +这个type是一个字符串,它指定了我们要创建DOM node节点的类型,tagName是你想要通过document.createElement创建HTML元素时传递给它的字符串;它也可以是个函数,但我们将它留给Step7 + +props是另一个对象,它具有JSX属性中的所有键和值。它还具有特殊属性:children。 + +children在本例中是一个字符串,但它通常是一个包含更多elements的数组。这就是为什么elements也是树。 + +我们需要替换的另一段React代码:ReactDOM.render。 + +render是 React 更改 DOM 的地方,所以让我们手动实现dom的更新。 + +首先我们使用element type属性创建了一个 DOM node ,在这个例子中是h1 。 + +然后我们将所有 element props 分配给这个DOM node,在这里是只有一个 title。 + +```javascript +const node = document.createElement(element.type) +node["title"] = element.props.title +``` +:::tip +为了避免混淆,我将使用 “element” 来指代 React元素,使用 “node” 来指代 DOM 元素。 +::: -### Step1: The createElement Function(创建函数组件) - -### Step2:render Function +然后,我们为子节点创建节点。我们只有一个字符串作为子节点,所以我们创建了一个文本节点。 -### Step3: Concurrent Mode (并行模式) -### Step4: Fibers +```javascript +const text = document.createTextNode("") +text["nodeValue"] = element.props.children +``` + +使用textNode而不是设置innerText,接下来我们以后以相同的方式处理。还要注意我们如何设置nodeValue标题,这个过程与给 h1 设置 title props类似,这就像是字符串中带有这样一个 props: {nodeValue: "hello"}。 + +最后,我们将textNode 添加至 h1,将h1添加至 container 。 + +现在我们有了和以前一样的app,但没有使用React。 + +```javascript +const element = { + type: "h1", + props: { + title: "foo", + children: "Hello", + }, +} +​ +const container = document.getElementById("root") +​ +const node = document.createElement(element.type) +node["title"] = element.props.title +​ +const text = document.createTextNode("") +text["nodeValue"] = element.props.children +​ +node.appendChild(text) +container.appendChild(node) +``` +--- +

Step1: The createElement Function(createElement 函数)

-### Step5: Render 和 Commit 阶段 -### Step6: Reconciliation (协调算法) +让我们从另一个app重新开始。这一次,我们将用我们自己的React版本替换官方React代码。 + +我们将编写自己的 createElement。 + +*让我们将 JSX 转换为 JS,这样我们就能实现 createElement 函数的调用了* + +正如我们在上一步中看到的,element是带有 type 和 props的对象。我们的函数唯一需要做的就是创建该对象。 + +```javascript +const element = React.createElement( + "div", + { id: "foo" }, + React.createElement("a", null, "bar"), + React.createElement("b") +); +``` +*我们使用扩展运算符处理props,children使用rest参数语法,这样children将始终是一个数组。* + +```javascript +function createElement(type, props, ...children) { + return { + type, + props: { + ...props, + children, + }, + } +} +``` +**举例:** +- createElement("div") 返回: + +```json +{ + "type": "div", + "props": { "children": [] } +} +``` +- createElement("div", null, a) + +```json +{ + "type": "div", + "props": { "children": [a] } +} +``` +- createElement("div", null, a, b) + +```json +{ + "type": "div", + "props": { "children": [a, b] } +} +``` +数组children还可以包含字符串或数字等原始值。因此我们为所有不是对象的内容创建一个独立的元素,并为其创建一个特殊的类型: TEXT_ELEMENT 。 + +```javascript +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: [], + }, + } +} +``` -### Step7: Function Components 函数组件 -### Step8: Hooks +--- +

Step2:render Function

+--- +

Step3: Concurrent Mode (并行模式)

+--- +

Step4: Fibers

+--- +

Step5: Render 和 Commit 阶段

+--- +

Step6: Reconciliation (协调算法)

+--- +

Step7: Function Components 函数组件

+--- +

Step8: Hooks