2. 环境搭建与 JSX
这是什么:JSX = 写在 JavaScript 里的 HTML 语法,让你能用熟悉的标签写法来描述页面结构。
为什么用:上一章的页面全是零散标签,正式组织代码前得先固定「起步姿势」。本章用公开 CDN 把 React 跑在一个普通 HTML 文件里——不用装任何东西。
如何用:本章先立「三行 CDN」的标准模板,跑一个计数器页面,再把 JSX 的五条规则背下来。
2.1 零工具起步:三行公开 CDN
免构建起步固定姿势:
- 引入三件套(公开 CDN,npmmirror 国内快):React 本体、ReactDOM 入口、Babel 编译器
- 页面里放一个空容器
<div id='root'>(React 接管把我们界面画进这里) - 写一个
<script type='text/babel' data-presets='react'>块——Babel 现场把这门 JS 里的 JSX 编译成浏览器认的代码
把下面的计数器整段贴进右侧「在线运行场」点运行,或存成 counter.html 双击打开:
<!DOCTYPE html>
<html lang='zh-CN'>
<head>
<meta charset='utf-8'>
<title>我的第一个 React 页面</title>
<script src='https://registry.npmmirror.com/react/18.3.1/files/umd/react.production.min.js'></script>
<script src='https://registry.npmmirror.com/react-dom/18.3.1/files/umd/react-dom.production.min.js'></script>
<script src='https://registry.npmmirror.com/@babel/standalone/7.29.11/files/babel.min.js'></script>
</head>
<body>
<div id='root'></div>
<script type='text/babel' data-presets='react'>
function App() {
const [count, setCount] = React.useState(0)
return (
<div>
<h1>我的第一个 React 页面</h1>
<button onClick={() => setCount(count + 1)}>
点了 {count} 次
</button>
</div>
)
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />)
</script>
</body>
</html>
你会看到:蓝色标题下一颗按钮「点了 0 次」,每点一下数字加一。
几个容易迷惑的点:
data-presets='react':给 Babel 指明「帮我编译 JSX」,选的就是官方@babel/preset-react- 免构建版没有 import:
React、ReactDOM是全局变量,钩子用React.useState(...)解构取 - Babel 编译是实时的:只适合学习;正式项目用构建工具提前编译(见第 8 章末尾)
2.2 JSX 的五条规则
JSX = JavaScript 写在 HTML 外面。规则背下来就能写:
① 必须有一个根(外层用 <></> 或 div 包住)
② class 写成 className(class 是 JS 保留字)
③ JS 表达式用 { } 插入
④ 样式用对象:style={{ color: 'steelblue' }}
⑤ 标签必须闭合(<img />、<br />)
记忆口诀:{ } 里是 JS,其余是 HTML;class 改 className,错误一般出在闭合。
2.3 五条规则的对照示例页
五条规则在同一个页面里各就各(注释对号入座),整段可跑:
<!DOCTYPE html>
<html lang='zh-CN'>
<head>
<meta charset='utf-8'>
<title>JSX 五条规则</title>
<script src='https://registry.npmmirror.com/react/18.3.1/files/umd/react.production.min.js'></script>
<script src='https://registry.npmmirror.com/react-dom/18.3.1/files/umd/react-dom.production.min.js'></script>
<script src='https://registry.npmmirror.com/@babel/standalone/7.29.11/files/babel.min.js'></script>
</head>
<body>
<div id='root'></div>
<script type='text/babel' data-presets='react'>
function Greeting() {
const name = '青蛙'
const user = null
return (
// ① 唯一根 <div> · ② class 写成 className
<div className='hello'>
<h1 style={{ color: 'steelblue' }}>你好,{name}</h1> {/* ③ 插值 · ④ 样式是对象套对象 */}
<p>{user ? '有用户' : '游客'}</p> {/* ③ 表达式就能算 */}
<img
style={{ width: '140px' }}
src='https://images.pexels.com/photos/1370740/pexels-photo-1370740.jpeg?auto=compress&cs=tinysrgb&w=320'
alt='青蛙'
/> {/* ④ 内联样式要对象 · ⑤ 自闭合 <img /> */}
</div>
)
}
ReactDOM.createRoot(document.getElementById('root')).render(<Greeting />)
</script>
</body>
</html>
你会看到:蓝色标题、灰色说明、正常显示的青蛙照片——注意 style={{ }} 是对象套对象,双大括号不是 Vue 的插值。
2.4 JSX 与 Vue 模板语法速查
| 你要做的 | Vue | React(JSX) |
|---|---|---|
| 显示变量 | {{ name }} |
{name} |
| 属性绑定 | :href="url" |
href={url} |
| 条件块 | v-if |
{ok ? <A/> : <B/>} |
| 列表 | v-for |
{arr.map(x => <li key={…}>)} |
| 绑事件 | @click="fn" |
onClick={fn} |
| 双向 | v-model |
手动 value + onChange(下一章) |
2.5 动手改
- 把 2.1 页面的按钮文案改成
{new Date().toLocaleDateString('zh-CN')} - 在 2.3 页面加一行
<p className='tip'>,用style={{ color: '#888' }}给它灰色 - 故意写
<div>abc不闭合,看 Babel 报什么错
2.6 小结
- 起步三件套三行公开 CDN +
<div id='root'>+text/babel块,零工具直接跑 - JSX 五规:唯一根 / className / { 表达式 } / 样式对象 / 必闭合
- Vue 模板六件套的 React 对应写法已可对照转换
下一章:组件基础 🐸