怎样徒手写一个React

本文通过手动实现一个简单的React,深入理解React 16.8的Fiber架构,涵盖JSX解析、虚拟DOM、Fiber工作单元及requestIdleCallback的应用,解析React性能优化的关键步骤。
摘要由CSDN通过智能技术生成

本文主要通过手写一个简单的 React,旨在了解 Facebook 团队使用两年多时间重构的 Fiber 架构到底做了些什么?从而对 React 基本原理有一个直观的认识。尬不多说,搭建开始~

青铜 – React、JSX、DOM elements 如何工作的?

本文主要基本 React 16.8 版本进行实现。

下面先实现一个最简单的页面渲染,快速了解 JSX、React、DOM 元素的联系。

import React from "react";
import ReactDOM from "react-dom";

const element = (
  <div id="foo">
    <a>bar</a>
    <b />
  </div>
);
const container = document.getElementById("root");
ReactDOM.render(element, container);

实现一个最简单的 React 应用,只需要上面的三行代码就够了 👆,下面我们也将拆分三步进行分析,

  1. 创建 React 元素(React Element)
  2. 获取根节点 root
  3. 将 React 元素渲染到页面上
1. JSX 是如何被解析的 - Babel
const element = (
  <div id="foo">
    <a>bar</a>
    <b />
  </div>
);

用 JSX 创建了一个 react 元素,它不是有效的 JS,其实它是被 babel 解析为如下代码:

"use strict";
const element = /*#__PURE__*/ React.createElement(
  "div",
  {
   
    id: "foo",
  },
  /*#__PURE__*/ React.createElement("a", null, "bar"),
  /*#__PURE__*/ React.createElement("b", null)
);

可以看到 Babel 会将 JSX 转换成 React.createElement() 方法,其中 createElement() 方法接收三个参数,分别是元素类型 type、元素属性 props、和子元素 children,后面我们会实现这个方法。

2. React 虚拟 DOM 对象的设计

React 的核心思想是在内存中维护一颗虚拟 DOM 树,当数据变化时更新虚拟 DOM,得到一颗新树,然后 Diff 新老虚拟 DOM 树,找到有变化的部分,得到一个 Change(Patch),将这个 Patch 加入队列,最终批量更新这些 Patch 到 DOM 中。

首先来看下基本的虚拟 DOM 结构:

const element = {
   
  type: "div",
  props: {
   
    id: "foo",
    children: [
      {
   
        type: "a",
        props: {
   
          children: ["bar"],
        },
      },
      {
   
        type: "b",
        props: {
   
          children: [],
        },
      },
    ],
  },
};

可以看出 React.createElement() 方法其实就是返回了一个虚拟 DOM 对象。下面我们来实现 createElement() 这个方法,

function createElement(type, props, ...children) {
   
  return {
   
    type,
    props: {
   
      ...props,
      children: children.map((child) =>
        // 这里我们区分下基本类型和引用类型,用 createTextElement 来创建文本节点类型
        typeof child === "object" ? child : createTextElement(child)
      ),
    },
  };
}

function createTextElement(text) {
   
  return {
   
    type: "TEXT_ELEMENT",
    props: {
   
      nodeValue: text,
      children: [],
    },
  };
}

可以看到通过 Babel 编译后的 element 对象,其实是对 React.createElement()的递归调用所返回的数据结构 - 一个嵌套的虚拟 DOM 结构。

3. 实现 render() 方法

有了虚拟 DOM 结构,接下来需要根据它来生成真实节点并渲染到页面上,也就是 render() 方法的工作。基本分为以下四步:

  • 创建不同类型节点
  • 添加属性 props
  • 遍历 children,递归调用 render
  • 将生成的节点 append 到 root 根节点上
function render(element, container) {
   
  // 1. 创建不同类型的DOM节点
  const dom =
    element.type == "TEXT_ELEMENT"
      ? document.createTextNode("")
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值