React 学习站
React›基础›入门

声明式 UI 与 JSX

入门基础

一句话定义

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}
stylestyle="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/声明:只能放表达式;逻辑提前到组件体里算好。

自测题

  1. <p>{user.bio}</p> 中 user.bio 为 undefined 时渲染出什么?和 null、0 各有什么区别?(undefined/null 都不渲染任何东西,0 会渲染出字符 "0"——这就是为什么 list.length && ... 有经典 bug。)
  2. 为什么 style={{ color: 'red' }} 有两层花括号?去掉一层会发生什么?
  3. 把下面 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>