一句话定义
JSX 是 JavaScript 的语法扩展:它长得像 HTML,但编译后就是函数调用——<div className="a">x</div> 被转成 createElement('div', { className: 'a' }, 'x'),产出普通的 JS 对象。
为什么重要
JSX 是 React「声明式描述 UI」的载体。理解「JSX 是对象不是 HTML」之后,条件渲染、循环、传 props 全部变成普通 JavaScript 问题,而不是模板语法问题。
前置知识
- kp-001 声明式心智模型。
- JS 表达式 vs 语句的区别(
if是语句、?:是表达式——这决定了 JSX 里能用哪个)。
核心概念
- JSX 是表达式:可以赋值、传参、放进数组。
- 编译目标:现代工具链(esbuild/Babel/SWC)将 JSX 转译为
jsx()/createElement()调用。 - 属性命名:
class→className,for→htmlFor;事件用onClick、onChange等驼峰名。 - 大小写敏感:小写开头被视为 HTML 标签,大写开头被视为组件。
原理 / 机制
编译示意(真实产物取决于工具链,但语义等价):
jsxconst el = <h1 className="title">Hello {name}</h1>;
// ↓ 编译后(等价)
const el = jsx('h1', { className: 'title' }, 'Hello ', name);
// jsx(...) 返回的是一个普通对象:{ type: 'h1', props: {...}, ... }
花括号 {} 是「逃逸回 JavaScript」的门。门里只能放表达式:
jsxfunction Profile({ user }) {
const greeting = `你好,${user.name}`;
return (
<div>
<h1>{greeting}</h1> {/* 变量:可以 */}
<p>{user.age >= 18 ? '成年' : '未成年'}</p> {/* 表达式:可以 */}
{/* {if (user.age >= 18) 'a' else 'b'} 语句:编译报错 */}
<p>{'共 ' + (1 + 2) + ' 项'}</p> {/* 括号防歧义 */}
</div>
);
}
语法规则速记:
| 规则 | 错误写法 | 正确写法 |
|---|---|---|
| 唯一根节点 | <a/><b/> | <><a/><b/></> 或数组 |
| class 属性 | class="x" | className="x" |
| 自闭合 | <img> | <img /> |
| 布尔属性 | disabled="false"(仍是 true) | disabled={false} |
| style | style="color: red" | style={{ color: 'red' }} |
直观类比
JSX 像带图纸批注的乐高说明书:每行代码既描述零件(标签)又允许你随时插一句 JavaScript 来决定装不装、装几个。HTML 模板引擎是「先写好说明书,数据来了填空」;JSX 是「说明书本身就是一段会算数的程序」。
实例 / 案例
JSX 与原生 JS 的等价转换,展示它「就是 JS」:
jsxconst items = ['apple', 'banana'];
const list = (
<ul>
{items.map((it, i) => (
<li key={it}>{i + 1}. {it}</li>
))}
</ul>
);
// 与下面完全等价:
const list = jsx('ul', null,
items.map((it, i) => jsx('li', { key: it }, `${i + 1}. ${it}`))
);
JSX 可以赋值给变量、作为函数返回值、放进对象——这就是「组件即函数」在语法层面的支持。
常见误区
- 以为 JSX 是模板字符串 / HTML:它编译成对象;所以没有「HTML 解析转义」那套问题,
{}里的内容默认不做 HTML 转义后插值,而是作为文本子节点安全渲染(XSS 默认被挡住,除非你用dangerouslySetInnerHTML)。 disabled={false}写成disabled="false":字符串 "false" 是真值,按钮依然禁用。- 忘记 key:列表渲染时控制台报警告,且复用行为错误(见 kp-009)。
- 在
{}里写if/for/声明:只能放表达式;逻辑提前到组件体里算好。
自测题
<p>{user.bio}</p>中user.bio为undefined时渲染出什么?和null、0各有什么区别?(undefined/null 都不渲染任何东西,0会渲染出字符 "0"——这就是为什么list.length && ...有经典 bug。)- 为什么
style={{ color: 'red' }}有两层花括号?去掉一层会发生什么? - 把下面 HTML 改写为合法 JSX:
<label for="q" class="s"><input type="text" disabled></label>
与其他知识点的关系
- 向前:kp-001 的「描述 UI」必须落地为 JSX 语法。
- 向后:kp-007 在此语法上实现条件/列表渲染;kp-009 解释列表里的 key;kp-024 里服务端组件的返回值同样是 JSX。
延伸阅读
- Writing markup with JSX:<https://react.dev/learn/writing-markup-with-jsx>
- JSX 深入(官方):<https://react.dev/learn/javascript-in-jsx-with-curly-braces>