从零到一:打造你的Mini-React (一)

前段时间,参加了崔哥的活动写一个mini-react,现在来对整个项目进行复盘和总结。

简介

在本篇文章中,我们将一起探索如何从零构建一个迷你版的React框架。通过这个过程,不仅能够加深对React内部机制的理解,还能学习到虚拟DOM、组件生命周期和状态管理等核心概念的实际应用。这篇文章旨在深入浅出地理解React工作原理。

问题清单
Q1:怎么处理jsx?
[Q2: 如果需要渲染数字,怎么处理?](#Q2: 如果需要渲染数字,怎么处理? "#eVH0V")


步骤拆分

简单渲染

我们先来看下react文档的案例

jsx 复制代码
import { createRoot } from 'react-dom/client';

// Clear the existing HTML content
document.body.innerHTML = '<div id="app"></div>';

// Render your React component instead
const root = createRoot(document.getElementById('app'));
root.render(<h1>Hello, world</h1>);

如果我们使用原生JS,可以得到:

jsx 复制代码
const app = document.createElement('div')
app.id = 'app'

const h1 = document.createElement('h1')
h1.textContent = 'Hello world'

app.appendChild(h1)

document.body.append(app)

我们能否用一种数据结构来描述整个结构树,并对渲染函数进一步抽象

  • 虚拟DOM(Virtual DOM)是对真实DOM的抽象表示,并且附加了额外的属性以优化React的更新过程。
jsx 复制代码
// vdom
const vdom = {
  type: 'div',
  props: {
    id: 'app',
    children: [
      {
        type: 'h1',
        props: {
          children: 'Hello world'
        }
      }
    ]
  }
}
jsx 复制代码
// App.jsx
// 这行一定要加上,vite编译时会转为React.createElement使用
import React from "./core/React"

function App() {
  return <h1>Hello, world</h1>
}

export default App

// main.js
import ReactDom from './core/ReactDOM';
import App from './App.jsx';


const root = ReactDom.createRoot(document.querySelector('#root'))
root.render(App)
jsx 复制代码
// React.js
function createElement(type, props, ...children) {
  return {
    type,
    props: {
      ...props,
      children: children.map((child) => {
        const isTextNode = typeof child === 'string'
        return isTextNode ? createTextNode(child) : child
      })
    }
  }
}
function createTextNode(text) {
  return {
    type: 'TEXT_ELEMENT',
    props: {
      nodeValue: text,
      children: []
    }
  }
}

function render(el, container) {
  // 处理函数组件
  if (typeof el === 'function') el = el()
  const dom =
    el.type === 'TEXT_ELEMENT'
      ? document.createTextNode('')
      : document.createElement(el.type)
  const isProperty = (key) => key !== 'children'
  Object.keys(el.props)
    .filter(isProperty)
    .forEach((name) => {
      dom[name] = el.props[name]
    })
  el.props.children.forEach((child) => {
    render(child, dom)
  })
  container.append(dom)
}

const React = {
  render,
  createElement
}

export default React
jsx 复制代码
// ReactDOM
import React from "./React.js";

// 返回一个对象包含render函数
const ReactDOM = {
  createRoot(container) {
    return {
      render(App) {
        React.render(App, container);
      },
    };
  },
};

export default ReactDOM;

Q1:怎么处理jsx

Vite 通过内置插件 @vitejs/plugin-react 来处理 JSX 文件。这个插件的具体作用是在构建阶段将 JSX 代码转换为 React.createElement 调用的形式。这样的转换使得浏览器可以执行转换后的代码,因为浏览器不能直接理解 JSX 语法。

至此,我们已经完成了将元素渲染到页面中

Q2: 如果需要渲染数字,怎么处理?

jsx 复制代码
function App() {
  return (
    <div>
      <h1>Hello, world!</h1>
      <h2>{123}</h2>
    </div>
  )
}

在我们的实现中,元素的创建是通过createElement函数来处理的。为了提高这一过程的健壮性和功能性,我们在现有的基础上添加对数字类型的处理。当检测到数字类型时,系统会自动将其转换为TextNode。

jsx 复制代码
function createElement(type, props, ...children) {
  return {
    type,
    props: {
      ...props,
      children: children.map((child) => {
        // number
        const isTextNode = typeof child === 'string'|| typeof child === 'number'
        return isTextNode ? createTextNode(child) : child
      })
    }
  }
}

总结

在本章节中,我们对从零开始构建一个迷你React框架的基本渲染功能进行了深入研究。我们实现了创建虚拟DOM的过程以及将虚拟DOM转换成实际DOM节点的机制------通常称为渲染(render)方法。此外,我们还阐明了JSX解析的基本原理。下一节,我们将实现批量更新的功能。

相关推荐
梦想平凡23 分钟前
百游棋牌源代码开发搭建教程(十):隔离部署、备份恢复与双端验收
java·前端·javascript·数据库·源代码管理
yume_sibai1 小时前
06-Rust Web 开发实战(Axum 框架 + 数据库 + JWT 认证 + 中间件 + 部署)
前端·数据库·rust
计算机魔术师3 小时前
特朗普上台打给黄仁勋:AI末日论是骗局,我们绝不让它发生
前端
troy1283 小时前
Python 基础语法(八):Web 后端开发、数据分析与可视化、网络爬虫、人工智能 / 大模型应用
前端·python·数据分析
计算机魔术师3 小时前
CEO说要慢下来,黑客说别做梦了——同一篇论文,两种命运
前端
kyriewen4 小时前
我花3天抓了一个幽灵bug,凶手藏在第4层
前端·javascript·程序员
IT_陈寒4 小时前
Java里用Stream.parallel()翻车实录,这性能还不如单线程
前端·人工智能·后端
wangchunyu1145 小时前
JavaScript 零基础入门教程
前端
hanchenxing5 小时前
前端异步任务三方案:Celery vs Redis Stream vs BullMQ 实战对比消息队列
前端·数据库·redis·异步任务·方案对比
默_笙5 小时前
⚓ AI 的"官方答题卡":withStructuredOutput 与结构化输出的终局之战
前端·javascript