JSX魔法揭秘:从魔法糖到React.createElement的奇幻之旅 ✨

107 阅读5分钟

JSX魔法揭秘:从魔法糖到React.createElement的奇幻之旅 ✨

JSX魔法封面图

一、JSX是什么?前端世界的"甜蜜魔法" 🍬

想象一下,你在JavaScript的世界里突然写起了HTML——这不是梦,这就是JSX!JSX(JavaScript XML)是React团队创造的一种语法扩展,它让你可以在JavaScript代码中直接书写类似HTML的结构。

// 这就是JSX!
const greeting = <h1 className="title">Hello, JSX魔法世界!</h1>;

JSX不是一种新语言,而是JavaScript的语法糖。就像咖啡加糖后更美味一样,JSX让React组件的编写变得更加甜美可口!

为什么React需要JSX?

  • UI与逻辑的完美融合:告别拼接HTML字符串的黑暗时代
  • 组件化思维:每个JSX片段都是自包含的UI单元
  • 开发体验升级:所见即所得,写UI就像写HTML一样直观
  • 类型安全:编译时就能发现标签拼写错误

二、JSX不能直接运行?需要Babel这位"魔法翻译官" 🧙‍♂️

如果你天真地以为浏览器能直接理解JSX,那就大错特错了!当我们尝试在原生JavaScript环境中运行JSX时:

// 尝试在原生JS中运行JSX
const element = <h1>Hello, world!</h1>; // 报错!

JSX原生运行报错

浏览器会一脸懵:"这是什么外星语法?" 这时,我们需要请出JavaScript世界的超级翻译官——Babel

三、Babel:让JavaScript永葆青春的"魔法泉" ⛲️

"Make JavaScript Great Again!" - Babel宣言

Babel是一位时光旅行者,它让开发者可以:

  1. 大胆使用最新JavaScript语法
  2. 无需等待浏览器厂商实现新特性
  3. 将现代代码"降级"为旧版本浏览器能理解的代码

让你不论是什么样的浏览器,都可以使用JS的最新版本!

Babel的魔法能力清单

转换类型示例转换后
JSX转换<div>Hello</div>React.createElement('div', null, 'Hello')
ES6箭头函数() => {}function() {}
Async/Awaitasync func() {}生成器+Promise实现
类属性class A { prop = 1 }构造函数中赋值

四、深入JSX转换魔法:从甜蜜糖衣到核心药丸 💊

4.1 JSX的底层真面目

每个JSX元素都在悄悄呼唤:"把我变成React.createElement吧!"

// 甜蜜的JSX糖衣
const element = <h1 className="title">Hello World</h1>;

// 剥开糖衣后...
const element = React.createElement(
  'h1',
  { className: 'title' },
  'Hello World'
);

4.2 为什么是className而不是class?

JSX转换前后对比 在JSX中,我们使用className而不是class,这背后有个小秘密:

// 这样写会报错!
const element = <h1 class="title">Hello</h1>;

// 正确写法
const element = <h1 className="title">Hello</h1>;

因为class是JavaScript的保留关键字(类关键字)!Babel在转换时:

// 转换后的代码
React.createElement('h1', { className: 'title' }, 'Hello');

五、实战:手把手演示JSX转换魔法 🧪

让我们搭建一个迷你实验室,亲眼见证JSX到createElement的魔法转变!

这是我们搭建需要的工具 Babel工作流程

5.1 创建魔法实验室(项目)

image.png

# 初始化项目
npm init -y
# 安装Babel魔法工具
pnpm install @babel/cli @babel/core -D
# 安装React(魔法源泉)
pnpm install react
# 正式转换,将1.jsx编译成我们想要的2.jsx
 ./node_modules/.bin/babel 1.jsx -o 2.jsx

提问

pnpm install @babel/cli @babel/core -D这里-D是起到了什么作用?(@babel/cli是命令行工具, @babel/core核心库)

解答

-D表示-D 开发阶段的依赖dev,上线后是不用的,与之对比的是pnpm install react,他所安装的是整个阶段的,包括开发和上线,可看下图配置对比 image.png

5.2 准备魔法原料(JSX文件)

创建src/1.jsx文件:

const element = <h1>Hello, world!</h1>;
const element2 = (
    <ul>
        <li key="abx1">1</li>
        <li key="tsc2">2</li>
        <li key="xda3">3</li>
    </ul>
)

5.3 施展转换咒语

./node_modules/.bin/babel 1.jsx -o 2.jsx

image.png 由于babel在./node_modules/.bin这个目录下,我的终端是在compile_jsx上打开的,所以使用这条命令,您可以根据你自己babel所在的目录调整命令

成功在src目录下创建了2.jsx

咦?为什么没有变化?因为我们还缺一个关键的魔法配方——Babel预设!给Babel设定转换的规则

5.4 添加JSX转换配方

pnpm install @babel/preset-react -D

表示你使用了 @babel/preset-react 这个 预设(Preset) ,它是一组 Babel 插件的集合,专门用于 转换 React 所需的语法

创建.babelrc配置文件:

image.png

{
  "presets": ["@babel/preset-react"]
}

5.5 见证奇迹时刻!

./node_modules/.bin/babel 1.jsx -o 2.jsx

转换结果:

const element = /*#__PURE__*/React.createElement("h1", null, "Hello, world!");
const element2 = /*#__PURE__*/React.createElement("ul", null, /*#__PURE__*/React.createElement("li", {
  key: "abx1"
}, "1"), /*#__PURE__*/React.createElement("li", {
  key: "tsc2"
}, "2"), /*#__PURE__*/React.createElement("li", {
  key: "xda3"
}, "3"));

image.png

六、深入魔法原理:React.createElement的三部曲 🎭

每个React.createElement调用都遵循固定模式:

React.createElement(
  type,      // 标签名或组件类型
  [props],   // 属性对象
  [...children] // 子元素
)

6.1 魔法解析:嵌套元素的转换

看一个复杂JSX如何被转换:

// JSX
const element = (
  <div>
    <h1>标题</h1>
    <p>段落内容</p>
  </div>
);

// 转换后
const element = React.createElement(
  "div",
  null,
  React.createElement("h1", null, "标题"),
  React.createElement("p", null, "段落内容")
);

6.2 为什么需要key属性?

在列表元素中,key帮助React识别哪些元素改变了:

// JSX
<ul>
  <li key="1">第一项</li>
  <li key="2">第二项</li>
</ul>

// 转换后
React.createElement("ul", null, 
  React.createElement("li", { key: "1" }, "第一项"),
  React.createElement("li", { key: "2" }, "第二项")
);

七、现代魔法实践:你不需要直接使用Babel 🧰

在实际项目中,我们通常使用更强大的魔法工具箱:

7.1 Create React App(官方魔杖)

npx create-react-app my-magic-app

7.2 Vite(闪电魔杖)

npm create vite@latest my-magic-app -- --template react

这些工具已经配置好Babel,让你专注于施展JSX魔法,而不必手动设置转换器。

八、魔法总结:JSX的完整旅程 🚀

让我们回顾JSX从编写到渲染的完整魔法旅程:

  1. 编写阶段:开发者书写JSX代码

    const App = () => <h1>Hello JSX</h1>;
    
  2. 编译阶段:Babel将JSX转换为React.createElement

    const App = () => React.createElement("h1", null, "Hello JSX");
    
  3. 渲染阶段:React将createElement对象转换为真实DOM

    // 伪代码
    const element = document.createElement('h1');
    element.textContent = 'Hello JSX';
    
  4. 挂载阶段:ReactDOM将DOM插入页面

    ReactDOM.render(element, document.getElementById('root'));
    

九、魔法思考题 🤔

  1. 为什么JSX组件名称必须大写开头?
  2. 如何在JSX中渲染原始HTML字符串?
  3. JSX和Vue的模板语法有何本质区别?
  4. 为什么说JSX其实是JavaScript的语法糖?

"任何足够先进的技术,初看都与魔法无异。" - Arthur C. Clarke

JSX正是这样的魔法——它抽象了复杂的DOM操作,让开发者可以用声明式的方式描述UI。现在你已经掌握了这种魔法的奥秘,去创造令人惊叹的前端魔法吧!🎩✨