前段时间系统学习了React,这里做一个知识梳理和技术要点总结。本文将以React项目入口文件为切入点,深入解析框架的核心运行原理,并重点探讨JSX的本质与实现机制。
一、项目入口文件解析
在基于React 18+创建的项目中,main.js作为应用入口文件承担着初始化的重要职责。其典型结构如下:
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'
createRoot(document.getElementById('root')).render(<App />)
这个入口文件中,在 createRoot 函数中传入根节点,并调用 render 函数,最终实现将组件挂载到根节点root上。
由此最为出发点,不难理解createRoot函数的大概逻辑是这样的
const createRoot = (container) => {
return {
render: (app) => {
// to do thind...
}
}
}
这里我们可能会有疑问,传进 render 中的函数组件 ,是怎么处理成虚拟dom的? 这里我们就需要简单解释一下,什么是jsx?为什么需要jsx?
理解JSX设计:为什么需要.jsx文件?
一、JSX不是真正的JavaScript
在写React时会发现一个现象:用普通.js文件写组件会报错,但改成.jsx文件可以。
举个例子,当你在代码里写这样的"HTML标签"时:
let button = <Button>Click me</Button>
由于JavaScript引擎无法解析这样的代码,所以这时就需要一个"翻译官"(比如Babel或esBuild),把这种混合HTML的写法转换成标准的JavaScript函数调用:
let button = React.createElement(Button, null, "Click me");
二、JSX的变身过程
一个更直观的例子:
// 你写的JSX
<div id="app">
<h1>Hello World</h1>
</div>
// 被转换为
React.createElement("div", { id: "app" },
React.createElement("h1", null, "Hello World")
);
最终会生成一个描述页面结构的虚拟DOM对象:
{
type: 'div',
props: {
id: 'app',
children: [{
type: 'h1',
props: {
children: 'Hello World'
}
}]
}
}
到这里就能明白,传入render中的函数组件 其实就是虚拟dom结构。
三、为什么要大费周章?
为什么不直接写React.createElement呢? 试想如果要描述一个复杂界面:
// JSX写法
<Page>
<Header />
<MainContent>
<Article />
<Sidebar />
</MainContent>
</Page>
// 原生写法
React.createElement(Page, null,
React.createElement(Header),
React.createElement(MainContent, null,
React.createElement(Article),
React.createElement(Sidebar)
)
);
显然JSX更接近我们熟悉的HTML结构,既提升了可读性,又降低了学习成本。这就像用"中文"写代码,再自动翻译成"英文"给机器执行。
四、现代工具链的配合
虽然本文以Vite的esBuild举例,但无论你使用Webpack、Rollup还是其他构建工具,核心流程都是相似的:
- 识别JSX语法
- 转换成React.createElement调用
- 生成虚拟DOM结构
- 最终渲染为真实DOM
这整套流程就像一条自动化生产线,开发者只需要关心如何用直观的JSX描述界面,后续的复杂转换都由工具链默默完成。