第 2 篇:JSX 与模板语法

作者:袖梨 2026-07-24

Vue 把 UI 写在 <template> 里,用指令(v-ifv-for:class)操作它。React 则完全相反:它把 UI 写进 JavaScript,这种语法叫 JSX。一开始会觉得别扭,但理解之后你会发现它异常灵活——因为它就是 JS,你会的所有 JS 技巧都能用。

第 2 篇:JSX 与模板语法


一、第一眼对比

Vue3 SFC:

 复制代码<template>
  <div class="card">
    <h2>{{ title }}</h2>
    <p v-if="desc">{{ desc }}</p>
  </div>
</template><script setup>
const title = 'Hello'
const desc = 'World'
</script>

React:

 复制代码function Card() {
  const title = 'Hello'
  const desc = 'World'  return (
    <div className="card">
      <h2>{title}</h2>
      {desc && <p>{desc}</p>}
    </div>
  )
}

注意三点:

  1. UI 直接 return 出来,和逻辑写在同一个函数里;
  2. 插值用单大括号 {title},不是 Vue 的双大括号 {{ }}
  3. class 要写成 className(因为 JSX 本质是 JS,class 是保留字)。

二、插值:{ } 里能放任何 JS 表达式

Vue 的 {{ }} 里也能写表达式,但 React 的 { } 更彻底——任何合法的 JS 表达式都行

 复制代码function Demo({ user, items }) {
  return (
    <div>
      <p>{user.name.toUpperCase()}</p>
      <p>{user.age >= 18 ? '成年' : '未成年'}</p>
      <p>{items.length} 个项目</p>
      <p>{new Date().getFullYear()}</p>
    </div>
  )
}

记住:{ } 里放的是表达式(有返回值的),不能放 iffor 这类语句。需要条件/循环时,用三元、&&.map()(下一节讲)。


三、属性绑定:告别 : 前缀

场景Vue3React
静态属性type="text"type="text"
动态属性:href="url"href={url}
布尔属性:disabled="isDisabled"disabled={isDisabled}

Vue 用 : 区分静态和动态,React 用是否加大括号来区分:引号是字符串,大括号是 JS 值。

 复制代码<img src={imageUrl} alt="头像" width={120} />
<button disabled={loading}>提交</button>

几个必须改名的属性

因为 JSX 是 JS,一些 HTML 属性名会和 JS 关键字冲突,需要改成驼峰:

HTML / VueReact
classclassName
for(label)htmlFor
tabindextabIndex
onclickonClick(驼峰事件)

四、class 与 style 绑定

这是 Vue 开发者最不习惯的地方,因为 Vue 提供了强大的对象/数组语法糖,而 React 需要你用纯 JS 拼。

class

 复制代码<!-- Vue3 -->
<div :class="{ active: isActive, 'text-danger': hasError }"></div>
<div :class="['base', isActive ? 'on' : 'off']"></div>
 复制代码// React:用模板字符串或三元自己拼
<div className={`base ${isActive ? 'on' : 'off'}`}></div>// 条件较多时,社区常用 clsx / classnames 库(对标 Vue 的对象语法)
import clsx from 'clsx'
<div className={clsx('base', { active: isActive, 'text-danger': hasError })}></div>

style

Vue 里 style 可以是字符串或对象;React 只接受对象,且属性用驼峰、值大多要带单位字符串:

 复制代码<!-- Vue3 -->
<div :style="{ color: 'red', fontSize: '14px' }"></div>
 复制代码// React
<div style={{ color: 'red', fontSize: '14px' }}></div>

注意那两层大括号:外层是 JSX 插值,内层是 JS 对象字面量。


五、根节点:Fragment 对应 Vue 的多根

Vue3 支持组件多根节点,React 也支持,但需要用 Fragment 包裹(避免多余的 DOM 层级):

 复制代码import { Fragment } from 'react'function List() {
  return (
    <>
      <li>A</li>
      <li>B</li>
    </>
  )
}

<>...</><Fragment>...</Fragment> 的简写,渲染出来不会产生额外 DOM 节点,等价于 Vue 的"透明"多根。


六、注释、原始 HTML 等细节

 复制代码function Demo({ html }) {
  return (
    <div>
      {/* 这是 JSX 里的注释,必须包在大括号里 */}      {/* Vue 的 v-html 等价物(同样注意 XSS 风险) */}
      <div dangerouslySetInnerHTML={{ __html: html }} />
    </div>
  )
}

React 故意把这个 API 起名叫 dangerouslySetInnerHTML,就是提醒你:像 Vue 的 v-html 一样,会有 XSS 风险,慎用。


七、JSX 的本质(理解这点就通透了)

JSX 只是语法糖,最终会被编译成普通函数调用:

 复制代码<h1 className="title">Hello</h1>
// 编译后 ≈
React.createElement('h1', { className: 'title' }, 'Hello')

它返回一个描述 UI 的普通 JS 对象(叫"React 元素")。所以 JSX 能像值一样被赋给变量、放进数组、当函数返回值——这正是 React 灵活性的来源

 复制代码function Demo({ isLoggedIn }) {
  // JSX 可以存进变量
  const greeting = isLoggedIn ? <p>欢迎回来</p> : <p>请登录</p>
  const buttons = ['保存', '取消'].map(t => <button key={t}>{t}</button>)  return <div>{greeting}{buttons}</div>
}

在 Vue 里你要靠 v-if/v-for 指令;在 React 里,这些都只是普通的 JS 变量和数组操作。


小结

  • JSX = 在 JS 里写 UI,插值用单 { },里面放表达式
  • class → className:attr="x" → attr={x},style 只收驼峰对象
  • class 多条件拼接推荐 clsx,找回 Vue 对象语法的手感。
  • 多根用 <>...</>(Fragment),v-html 对应 dangerouslySetInnerHTML
  • 本质上 JSX 返回普通 JS 对象,所以 UI 可以当变量传来传去。

下一篇讲组件与 Props——看看 React 如何定义组件、如何声明和传递 props。

相关文章

精彩推荐