Skip to content
This page has been auto-translated and may contain errors.View in English

JSX

用纯 JavaScript 构建哪怕是一小块 UI 都需要拆分成多个步骤:创建元素、设置类名、设置文本,最后把它挂到页面上。标记和驱动它的代码分开放着,UI 越复杂就越难保持同步。JSX 解决了这个问题:标记直接写在 JavaScript 里,紧密到足以让你随时混用它们,而不用分开放模板和脚本。

JavaScript 中的标记

既然 JSX 是 JavaScript,你可以把任何 JavaScript 表达式扔进去,只需用花括号 {} 包起来。变量、函数调用、一点儿数学计算,任何你需要的值,都可以直接塞到标记里,代替你原本写的静态文本。

jsx
const name = 'Ada'
return <p className="greeting">Hello, {name}</p>

这里 {name} 会在渲染时被 name 变量的值替换掉,所以页面显示的是 "Hello, Ada"。花括号外的所有东西都是标记;花括号内的,你又回到了纯 JavaScript。

JSX 有几条规则。大多数属性用 camelCase 而不是 HTML 的小写加连字符形式,所以是 classNamehtmlFortabIndex,而不是 classfortabindex;ARIA 和 data- 属性保持连字符,比如 aria-hiddendata-testid。每个标签都要闭合,包括在 HTML 中会留开的那些,所以 <img /><br /> 都要加上那个反斜杠。一个组件只能返回一个根元素。如果你需要返回并排的两个元素又不想用额外的 <div> 包装它们,用 fragment 包起来,写法是空的尖括号:

jsx
return (
  <>
    <h1>Title</h1>
    <p>Some text</p>
  </>
)

JSX 与 HTML 的差异

JSX 看起来接近 HTML,但差异足够细微,以至于你没察觉到时就被绊倒了。属性名是第一个差异:class 变成 className,因为 class 在 JavaScript 中是保留字。style 属性也不同:在 HTML 中它是 CSS 字符串,在 JSX 中它接收一个 JavaScript 对象,属性名用 camelCase,值是字符串。

jsx
<div style={{ backgroundColor: 'lightblue', fontSize: '18px' }}>Styled</div>

外层的 {} 就是嵌入任何表达式的那个,内层的 {} 是被嵌入的对象字面量,这就是为什么 JSX 中的 style 属性最后会有两个花括号连在一起。

另一个差异是 {} 内部允许什么。它只接受 表达式,也就是产生值的东西,像变量、函数调用或三元操作符。它不接受语句,所以 iffor 循环不能直接放在你标记里的花括号中。当你需要那种逻辑时,在 return 之前运行它,然后嵌入结果。

幕后来看,JSX 在到达浏览器前被编译成纯 JavaScript 函数调用。这更多是工具细节,你日常中不会频繁想到,Beyond the basics 这一章在 React 的其他内容都说清楚后会回到这点。

JSX 是语法糖。编译器把每个元素变成一个 React.createElement 调用,或者用这个课程工具采用的自动 JSX 运行时(自 React 17 起的标准,也是任何现代配置的默认选项)来说,是构建工具生成的等价调用,你不需要 React 在作用域内。那个早前的例子编译后类似于 React.createElement('p', { className: 'greeting' }, 'Hello, ', name)

编译步骤正是 {} 只能放表达式的原因。每个 {} 变成传给那个函数调用的一个参数,而函数参数必须计算出一个值。iffor 这样的语句不产生值,所以它不能出现在参数位置。三元操作符能内联使用是因为它是表达式;if 不能是因为它是语句。当逻辑复杂到三元操作符放不下时,在 return 上方用一个变量计算出值,然后嵌入那个变量。

JunoJSX 是混有 JavaScript 的标记 关键要点:{} 是你从标记内部回到 JavaScript 的门道。这些花括号之间的任何东西都是一个值、一个变量、一个计算、一个函数调用,它会直接放到页面上。其他的都是由此而来:className 替代 class,每个标签都闭合,一个 return 返回一个根元素。
JunoJSX 是混有 JavaScript 的标记{} 看作你的表达式位置:变量、函数调用、三元操作符,都没问题;像 if 这样的语句不行。结合命名上的差异,classNamehtmlForstyle 作为对象,JSX 就不再像是 HTML 的变体,而像是穿了标记语法外壳的 JavaScript。
JunoJSX 是混有 JavaScript 的标记 每个 {} 编译成一个函数参数,这正是表达式在那里工作而语句不工作的全部原因。记住这个心智模型,JSX 的其他怪癖,camelCase 属性、style 对象、自闭合标签,就不再像是武断的规则,而像是"这实际上是伪装的 React.createElement 调用"的后果。

接下来:样式组件,让这些元素有外观。