怎样徒手写一个React

本文通过手动实现一个简单的React,深入理解React 16.8版本的Fiber架构。从JSX解析、虚拟DOM设计到Fiber的中断渲染和工作单元,逐步剖析React的基本原理和优化策略,帮助读者直观认识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(<
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值