乐于分享
好东西不私藏

React开发:从 Vue 模板到 React的JSX/TSX,语法对照 + 快速适配指南

React开发:从 Vue 模板到 React的JSX/TSX,语法对照 + 快速适配指南
对于习惯了 Vue 模板语法的开发者来说,初次接触 JSX/TSX 往往会感到陌生:没有指令、没有双大括号专属规则、写法更贴近原生 JavaScript,这让很多人望而却步。
但事实上,JSX/TSX 和 Vue 模板的核心逻辑完全相通,只是语法表现形式不同。插值、条件渲染、列表循环、事件绑定、属性绑定…… 这些你在 Vue 中烂熟于心的功能,在 JSX/TSX 中都有一一对应的写法。
本文将以 Vue 模板语法为对标基准,对 JSX/TSX 核心语法进行逐点精讲,用你最熟悉的思维方式,无痛过渡到 JSX/TSX 开发,让你快速掌握两种语法的互通逻辑,轻松应对 React、Vue 渲染函数等场景。

一、核心区别

1、区别总览

特性

Vue 模板

React JSX/TSX

本质

HTML 扩展,有专属指令v-if/v-for

JavaScript 扩展,没有指令,全用原生 JS

动态值

{{ }}

{ }

逻辑写法

模板写指令,逻辑写 script

模板里直接写 JS 逻辑

绑定属性

:attr

attr={ }

事件

@event

onEvent

循环

v-for

数组.map()

条件

v-if

&& / 三元表达式

2、基础语法详解

(1)文本插值

Vue
<span>{{ message }}</span>
Mustache 语法,双大括号渲染变量。
React
<span>{message}</span>
  • 所有动态内容必须用 {} 包起来
  • 字符串、数字、变量、表达式都能放
  • 不能写 if/for(这是语句,不是表达式)

(2)属性绑定

Vue
<img :src="imgUrl" /><div :class="className"></div>
用 : 或 v-bind: 绑定动态属性。
React
<imgsrc={imgUrl} /><divclassName={className}></div>
重点注意
  • class → className
  • JSX 里 class 是关键字,不能用
  • for → htmlFor
  • <label for="name"> → <label htmlFor="name">

  • 所有属性都用小驼峰
  • maxlength → maxLength
  • autofocus → autoFocus

(3)动态class 绑定

Vue
<div :class="{ active: isActive }"></div><div :class="[baseClass, activeClass]"></div>
React
//方式 1:三元表达式(最常用)<div className={isActive ? 'active' : ''}></div>//方式 2:数组拼接<divclassName={[baseClass,isActive && active].filter(Boolean).join(' ')}></div>//方式 3:推荐库 classnames(企业级)import classNames from 'classnames'<div className={classNames('base', { active: isActive })}></div>

(4)动态style 绑定

Vue
<div :style="{ color: textColor, fontSize: '14px' }"></div>
React
<divstyle={{color:textColorfontSize: '14px' }}></div>
规则
  • 外层 {} 表示 “这里是 JS”
  • 内层 {} 是样式对象
  • CSS 属性用小驼峰
font-size → fontSize
background-color → backgroundColor
  • 字符串必须加引号

3、条件渲染

Vue:v-if / v-else-if / v-else
<divv-if="score >= 90">优秀</div><divv-else-if="score >= 60">及格</div><divv-else>不及格</div>
React:两种写法
//写法 1:三元表达式(支持多条件)<div>  {score >= 90 ? '优秀' : score >= 60 ? '及格' : '不及格'}</div>//写法 2:&& 逻辑(只做显示 / 隐藏){isShow && <div>我会显示</div>}
原理
  • true && 组件 → 返回组件
  • false && 组件 → 返回 false,不渲染
禁止写法
if (isShow) <div/> } // 错误!JSX 里不能直接写 if 语句
正确复杂条件写法
function getContent() {  if (score >= 90return <div>优秀</div>  if (score >= 60return <div>及格</div>  return <div>不及格</div>}<div>{getContent()}</div>

4、列表循环

Vue:v-for
<ul>  <liv-for="item in list":key="item.id">{{ item.name }}</li></ul>
React:array.map()
<ul>  {list.map((item) => (    <likey={item.id}>{item.name}</li>  ))}</ul>
必须记住3 条规则
  • 循环必须用 map,不能用 for 语句
  • 必须加 key,放在最顶层元素上
  • map 必须有返回值(用括号 () 包裹 JSX)
带索引index
{list.map((item, index) => (  <likey={index}>{item.name}</li>))}

5、事件绑定

(1)语法示例

Vue
<button @click="handleClick">点击</button><input @input="handleInput" />
React
<buttononClick={handleClick}>点击</button><inputonInput={handleInput} />

(2)事件名对照表

Vue

React

@click

onClick

@input

onInput

@change

onChange

@submit

onSubmit

@keyup

onKeyUp

@mousedown

onMouseDown

(3)传参方式

Vue
<button @click="handleClick(id)">点击</button>
React
<buttononClick={() => handleClick(id)}>点击</button>
️注意
  • 不能直接写 onClick={handleClick(id)}
  • 会自动执行,不是绑定事件!

6、v-model 双向绑定 → React 受控组件

Vue
<inputv-model="text" />
React
const [text, setText] = useState('')<input value={text} onChange={(e) => setText(e.target.value)} />
拆解
  • value={text}:把状态绑定到输入框
  • onChange:输入时更新状态
  • React 没有双向绑定,是单向数据流
复选框
<inputtype="checkbox"checked={isChecked}onChange={(e) => setIsChecked(e.target.checked)}/>

7、v-show 显示隐藏

Vue
<divv-show="isShow">内容</div>
React
<div style={{ display: isShow ? 'block' : 'none' }}>内容</div>
区别
  • v-if:销毁 / 重建
  • v-show / React 版:display 控制显示隐藏

8、v-html → 危险 HTML

Vue
<divv-html="html"></div>
React
<divdangerouslySetInnerHTML={{__html:html }} />
名字带 dangerously 是提醒你:小心 XSS 攻击

9、计算属性→ React useMemo

Vue
computed: {  fullName() {    return this.firstName + ' ' + this.lastName  }}
React
import { useMemo } from 'react'const fullName = useMemo(() => {  return firstName + ' ' + lastName}, [firstName, lastName])
简单计算可以不用useMemo
const fullName = firstName + ' ' + lastName

10、侦听watch → React useEffect

Vue
watch(count, (newVal) => {  console.log('count 变了', newVal)})
React
useEffect(() => {  console.log('count 变了', count)}, [count])
依赖规则
  • [count] → 只监听 count
  • [] → 只执行一次(如 mounted)
  • 不写依赖→ 每次更新都执行

11、插槽Slot → React children / Props

(1)默认插槽

Vue
<Card>这里是内容</Card><!-- 子组件 --><div><slot /></div>
React
<Card>这里是内容</Card>// 子组件function Card({ children }) {  return <div>{children}</div>}

(2)具名插槽

Vue
<Card>  <template #header>标题</template>  <template #default>内容</template></Card>
React
<Card header={<div>标题</div>}>内容</Card>// 子组件function Card({ header, children }) {  return (    <div>      <divclassName="header">{header}</div>      <divclassName="body">{children}</div>    </div>  )}

12、生命周期完整对照

阶段

Vue3

React

挂载完成

onMounted

useEffect(() => {}, [])

更新

watch

useEffect(() => {})

卸载

onUnmounted

useEffect(() => { return () => {} })

二、避坑与模版示例

1、所有变量/ 表达式必须用 {} 包裹

错误
<span>message</span>
正确
<span>{message}</span>

2、class 必须改成 className

错误
<divclass="box"></div>
正确
<divclassName="box"></div>

3、for 必须改成 htmlFor

错误
<labelfor="name">姓名</label>
正确
<labelhtmlFor="name">姓名</label>

4、行内样式必须写style={{ }} 双层大括号

错误
<divstyle="color:red"></div><divstyle={color:red}></div>
正确
<div style={{ color: 'red', fontSize: '14px' }}></div>

5、循环必须用map + 必须加 key

错误
<li v-for="item in list"></li>{for (let i=0;i<list.length;i++){}}
正确
{list.map(item => (<likey={item.id}>{item.text}</li>))}

6、事件名必须是小驼峰(onXxx)

错误
<button @click="fn"onclick="fn">点击</button>
正确
<buttononClick={fn}>点击</button>

7、事件传参必须用箭头函数包裹

错误(会自动执行,页面一加载就触发)
<buttononClick={fn(id)}>点击</button>
正确
<buttononClick={() => fn(id)}>点击</button>

8、JSX 注释必须写 {/* 注释内容 */}

错误
// 注释<!-- 注释 -->
正确
{/* 这是 JSX 里唯一正确的注释写法 */}

9、组件必须返回唯一根节点(用<> 空标签)

错误(返回多个并列元素,报错)
return (  <div>1</div>  <div>2</div>)
正确
return (  <>    <div>1</div>    <div>2</div>  </>)

10、if / for 语句不能直接写在 JSX 里

错误
{if (isShow) <div></div>}{for (let x in list) {}}
正确
// 条件:&& / 三元 / 外部函数{isShow && <div></div>}// 循环:map{list.map(...)}

11、模版示例

Vue 组件
<template>  <div>    <inputv-model="text"placeholder="输入内容" />    <button @click="addItem">添加</button>    <ul>      <liv-for="item in list":key="item.id":class="{ active: item.active }">        {{ item.text }}      </li>    </ul>  </div></template><scriptsetup>import { ref } from 'vue'const text = ref('')const list = ref([  { id1text'测试'activefalse }])const addItem = () => {  list.value.push({    idDate.now(),    text: text.value,    activefalse  })  text.value = ''}</script>
React 等价 TSX 组件
import { useState } from 'react'export default function Demo() {  const [text, setText] = useState('')  const [list, setList] = useState([    { id1text'测试'activefalse }  ])  const addItem = () => {    setList([      ...list,      { idDate.now(), text, activefalse }    ])    setText('')  }  return (    <div>      <input        value={text}        onChange={(e) => setText(e.target.value)}        placeholder="输入内容"      />      <buttononClick={addItem}>添加</button>      <ul>        {list.map((item) => (          <li            key={item.id}            className={item.active ? 'active: ''}          >            {item.text}          </li>        ))}      </ul>    </div>  )}

三、写在最后

1、JSX 中变量、表达式需用大括号包裹

2、标签 class 属性统一改为 className,label 的 for 属性改为 htmlFor

3、行内样式使用双层大括号 style={{}},样式属性采用小驼峰写法

4、列表渲染使用数组 map 方法,渲染项必须设置 key 属性

5、事件名称使用小驼峰格式,如 onClick、onChange

6、事件需要传参时,通过箭头函数包裹调用方法

7、JSX 内部注释需使用 {/* 注释内容 */} 格式

8、组件渲染内容必须包裹在单个根节点中,可使用空标签 <> </>

9、JSX 区域内不能直接书写 if、for 等语句,改用表达式或外部函数实现逻辑

如果本文对你有帮助,不妨点个赞,关注一下~欢迎在评论区留言交流,一起学习进步,共同成长!
注:本文为个人原创,AI 仅提供辅助支持。