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

JSX

用纯 JavaScript 构建即使是一个小的 UI 也意味着要处理分散的步骤:创建元素、设置它的 class、设置文本,然后将它附加到页面上。标签和驱动它的代码各自分离,随着 UI 的增长,保持它们同步变得越来越困难。JSX 弥补了这个间隙:标签直接存在于你的 JavaScript 中,足够接近,你可以自由地混合它们,而不用把模板和脚本分开。

在 JavaScript 中编写标签

因为 JSX 是 JavaScript,你可以通过用花括号 {} 包装任何 JavaScript 表达式来把它放进 JSX 中。一个变量、一个函数调用、一些数学运算,任何你需要的值,都可以直接放入标签中,替代静态文本。

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 函数调用。这更多是一个工具细节,而不是你日常会想到的东西,深入了解 章节在 React 其他部分就位后会再讲到这个。

JSX 是语法糖。编译器把每个元素转变成对 React.createElement 的调用,或者用这个课程工具使用的自动 JSX runtime(自 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 调用"这个事实的自然后果。

接下来:样式化组件,给这些元素添加外观。