React 核心基础
前端框架 React JSX一、什么是 React
1.1 官方定义
React — A JavaScript library for building user interfaces. — reactjs.org
React 是 Facebook 开发的 前端框架,用于构建可复用、高效的用户界面。
1.2 为什么选择 React
| 维度 | 说明 |
|---|---|
| 流行度 | StackOverflow 调查中最受欢迎的 Web 框架(仅次于 jQuery) |
| 就业 | Airbnb、Uber、Facebook、Netflix 均使用 React |
| 趋势 | Google Trends 中远超 Angular 和 Vue |
| 生态 | NPM 包丰富、社区活跃、学习资源多 |
1.3 React 的核心优势
组件化(Components)
将复杂 UI 分解为 独立、可复用 的组件树:
App
├── NavBar
├── ToDoList
│ ├── ListItem
│ │ ├── Checkbox
│ │ └── ItemText
│ └── ListItem
└── Footer每个组件 = HTML 结构 + CSS 样式 + JS 逻辑 的封装体。
对比传统开发
<!-- Bootstrap Navbar — 一大堆 HTML -->
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="#">Brand</a>
<button class="navbar-toggler" type="button" ...>
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" ...>
<!-- 更多嵌套... -->
</div>
</nav>
<!-- React — 一行搞定 -->
<NavBar />虚拟 DOM 与高效渲染(Diffing)
旧 DOM 树 新 DOM 树
┌─────────┐ ┌─────────┐
│ App │ │ App │
│ ┌─────┐ │ │ ┌─────┐ │
│ │ □ │ │ →→→ │ │ ☑ │ │ ← 只有这个变了
│ └─────┘ │ │ └─────┘ │
│ ┌─────┐ │ │ ┌─────┐ │
│ │ text │ │ │ │ text │ │ ← 不变,不重新渲染
│ └─────┘ │ │ └─────┘ │
└─────────┘ └─────────┘
React 只更新有变化的部分 → 更高效 → 更快独立组件更新
每个组件可 独立 与服务器通信并更新自身,不影响其他组件:
- Twitter:滚动到底部 → 只有 Feed 组件请求新数据
- Facebook:新评论 → 只有对应 Post 组件更新
二、JSX 与 Babel
2.1 什么是 JSX
JSX = JavaScript XML — 允许在 JavaScript 文件中直接编写 HTML。
// index.js — 这是一个 JavaScript 文件!
import React from "react";
import ReactDOM from "react-dom";
// 在 JS 中写 HTML — 这就是 JSX 的魔力
ReactDOM.render(
<h1>Hello World!</h1>,
document.getElementById("root")
);2.2 Babel 编译器
JSX 不是合法的 JavaScript。Babel 负责将 JSX 编译为浏览器能理解的 JS:
JSX:
<h1>Hello World!</h1>
↓ Babel 编译
JavaScript:
React.createElement("h1", null, "Hello World!")没有 Babel/React 的等效写法:
// ❌ 不用 JSX — 冗长、难读
var h1 = document.createElement("h1");
h1.innerHTML = "Hello World!";
document.getElementById("root").appendChild(h1);
// ✅ 用 JSX — 简洁、直观
ReactDOM.render(<h1>Hello World!</h1>, document.getElementById("root"));💡 Babel 还能将 ES6/ES7/ES8 编译为兼容所有浏览器的 JavaScript,包括 IE。
2.3 基本结构
<!-- index.html -->
<html>
<head>
<title>React App</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<!-- React 组件挂载点 -->
<div id="root"></div>
<script src="./src/index.js" type="text/jsx"></script>
</body>
</html>// index.js
import React from "react";
import ReactDOM from "react-dom";
ReactDOM.render(
<h1>Hello World!</h1>,
document.getElementById("root")
);2.4 render() 规则
ReactDOM.render() 只能接受一个 HTML 元素:
// ❌ 两个元素 → 报错
ReactDOM.render(
<h1>Hello</h1>
<p>World</p>,
document.getElementById("root")
);
// ✅ 包裹在 div 中 → 一个元素
ReactDOM.render(
<div>
<h1>Hello</h1>
<p>World</p>
</div>,
document.getElementById("root")
);三、JSX 中的 JavaScript 表达式
3.1 花括号注入
在 JSX 中用 {} 插入 JavaScript 表达式:
const name = "Angela";
const num = 7;
ReactDOM.render(
<div>
<h1>Hello {name}!</h1>
<p>Your lucky number is {num}</p>
</div>,
document.getElementById("root")
);3.2 表达式 vs 语句
// ✅ 表达式 — 会产生一个值
{2 + 3} // → 5
{Math.floor(Math.random() * 10)} // → 随机数
{name.toUpperCase()} // → "ANGELA"
// ❌ 语句 — 不能放在 {} 中
{if (name === "Angela") return 7} // 报错!3.3 ES6 模板字面量
const fName = "Angela";
const lName = "Yu";
// 方式 1 — 多个花括号
<h1>Hello {fName} {lName}!</h1>
// 方式 2 — 字符串拼接
<h1>Hello {fName + " " + lName}!</h1>
// 方式 3 — 模板字面量(不推荐嵌套太深)
<h1>Hello {`${fName} ${lName}`}!</h1>3.4 动态年份实战
const year = new Date().getFullYear();
ReactDOM.render(
<p>Copyright ⓒ {year}</p>,
document.getElementById("root")
);
// 输出:Copyright ⓒ 2026(自动更新)常见错误
// ❌ 忘记加 () — 传入的是函数引用,不是返回值
{new Date().getFullYear} // → 报错:函数不是有效的 React 子元素
// ✅ 加上 () 调用方法
{new Date().getFullYear()} // → 2026四、JSX 属性与样式
4.1 属性命名规则
JSX 属性使用 camelCase(驼峰),而非 HTML 的全小写:
| HTML 属性 | JSX 属性 |
|---|---|
class | className |
contenteditable | contentEditable |
spellcheck | spellCheck |
tabindex | tabIndex |
for | htmlFor |
// ❌ HTML 风格 — 会产生警告
<h1 class="heading" contenteditable="true">Hello</h1>
// ✅ JSX 风格 — 正确
<h1 className="heading" contentEditable={true} spellCheck={false}>Hello</h1>4.2 className 样式(推荐)
/* styles.css */
.heading {
color: red;
font-size: 24px;
font-weight: bold;
}
.food-img {
width: 100px;
height: 100px;
}<h1 className="heading">My Favorite Foods</h1>
<img className="food-img" src="..." alt="bacon" />4.3 内联样式(JavaScript 对象)
内联样式的值必须是 JavaScript 对象,不是字符串:
// ❌ HTML 字符串形式 — 报错
<h1 style="color: red">Hello</h1>
// ✅ JavaScript 对象形式(双花括号)
<h1 style={ {color: "red"} }>Hello</h1>
// ↑外层{} = JSX注入 ↑内层{} = JS对象4.4 CSS 属性名转换
CSS 属性也使用 camelCase,值为 字符串,分隔用 逗号(非分号):
const customStyle = {
color: "red",
fontSize: "20px", // font-size → fontSize
border: "1px solid black", // 含空格的值用字符串
backgroundColor: "#f0f0f0" // background-color → backgroundColor
};
<h1 style={customStyle}>Hello</h1>4.5 内联样式的使用场景
内联样式的最大优势 = 动态更新:
const customStyle = { color: "" };
if (currentTime < 12) {
customStyle.color = "red"; // 早上 → 红色
} else if (currentTime < 18) {
customStyle.color = "green"; // 下午 → 绿色
} else {
customStyle.color = "blue"; // 晚上 → 蓝色
}
<h1 className="heading" style={customStyle}>
{greeting}
</h1>4.6 自闭合标签
JSX 中没有子元素的标签 必须 自闭合:
// ❌ HTML 可以不闭合 — JSX 不行
<img src="..." alt="photo"> // 报错:Unterminated JSX
// ✅ 必须自闭合
<img src="..." alt="photo" />
<br />
<hr />
<input />五、React 组件
5.1 函数组件
组件本质是一个 返回 JSX 的函数,名称使用 PascalCase:
// Heading.jsx
import React from "react";
function Heading() {
return <h1>My Favorite Foods</h1>;
}
export default Heading;5.2 使用组件
// 自定义组件 → PascalCase → React 区分于 HTML 原生标签
<Heading /> // ✅ 自定义组件(大写开头)
<heading /> // ❌ 会被解析为 HTML <heading> 标签
// 没有子元素 → 自闭合标签
<Heading /> // ✅
<Heading></Heading> // ✅ 也可以,但不推荐5.3 组件拆分
将大文件拆分为独立的组件文件:
src/
├── index.js # 入口文件(渲染 App)
└── components/
├── App.jsx # 根组件
├── Heading.jsx # 头部组件
└── List.jsx # 列表组件index.js — 只负责渲染:
import React from "react";
import ReactDOM from "react-dom";
import App from "./components/App";
ReactDOM.render(<App />, document.getElementById("root"));App.jsx — 组件树根节点:
import React from "react";
import Heading from "./Heading";
import List from "./List";
function App() {
return (
<div>
<Heading />
<List />
</div>
);
}
export default App;Heading.jsx — 独立组件:
import React from "react";
function Heading() {
return <h1>My Favorite Foods</h1>;
}
export default Heading;💡 每个组件文件都必须
import React,因为 JSX 编译依赖 React 模块。
六、ES6 Import / Export 模块
6.1 默认导出(Default Export)
每个文件只能有 一个 默认导出,导入时 可以任意命名:
// math.js
const pi = 3.1415962;
export default pi;
// index.js
import pi from "./math"; // ✅
import PI from "./math"; // ✅ 任意名称都可以
import myNumber from "./math"; // ✅ 仍然是 3.14...6.2 命名导出(Named Export)
一个文件可以有 多个 命名导出,导入时 名称必须匹配:
// math.js
const pi = 3.1415962;
function doublePi() {
return pi * 2;
}
function triplePi() {
return pi * 3;
}
export default pi;
export { doublePi, triplePi };
// index.js
import pi, { doublePi, triplePi } from "./math";
// ↑ 默认导出 ↑ 命名导出(名称必须一致)6.3 通配符导入
import * as calculator from "./math";
calculator.default; // → 3.1415962
calculator.doublePi(); // → 6.2831924
calculator.triplePi(); // → 9.4247886不推荐通配符导入
通配符导入会失去默认导出的便利性,且导入了可能不需要的内容。 建议使用明确的命名导入。
6.4 require vs import
| 特征 | require(Node.js) | import(ES6) |
|---|---|---|
| 来源 | Node.js 原生 | ECMAScript 标准 |
| 语法 | const x = require("module") | import x from "module" |
| 同步/异步 | 同步 | 可异步 |
| 浏览器兼容 | ❌ 需要打包工具 | ✅ 通过 Babel 编译 |
| React 推荐 | ❌ | ✅ |
七、本地开发环境搭建
7.1 前提条件
# 检查 Node 版本(需要 12+)
node --version7.2 创建 React 应用
npx create-react-app my-app
# npx = npm 的包运行器,无需全局安装
cd my-app
npm start
# → 自动打开 http://localhost:30007.3 项目清理
创建后删除不必要的模板文件,保留核心结构:
my-app/
├── public/
│ └── index.html # 只保留这一个
└── src/
└── index.js # 只保留这一个清理后的 index.html:
<!DOCTYPE html>
<html>
<head>
<title>React App</title>
</head>
<body>
<div id="root"></div>
<script src="./src/index.js" type="text/jsx"></script>
</body>
</html>清理后的 index.js:
import React from "react";
import ReactDOM from "react-dom";
ReactDOM.render(<h1>Hello World!</h1>, document.getElementById("root"));7.4 文件命名约定
| 文件 | 命名 | 说明 |
|---|---|---|
| 入口文件 | index.js | 保持 .js 扩展名 |
| 组件文件 | Heading.jsx 或 Heading.js | 两种都可以,保持一致即可 |
| 样式文件 | styles.css | 标准 CSS |
💡 AirBnB 规范 推荐
.jsx扩展名,但实际上两者功能相同。选择一种并保持一致。
八、速查表
| 概念 | 语法/用法 |
|---|---|
| 渲染元素 | ReactDOM.render(<h1>Hi</h1>, document.getElementById("root")) |
| JSX 注入 JS | <h1>Hello {name}</h1> |
| className | <div className="my-class"> |
| 内联样式 | <h1 style={ { color: "red", fontSize: "20px" } }> |
| 函数组件 | function App() { return <div>...</div>; } |
| 默认导出 | export default App; |
| 默认导入 | import App from "./App"; |
| 命名导出 | export { fn1, fn2 }; |
| 命名导入 | import { fn1, fn2 } from "./file"; |
| 自闭合标签 | <img /> <br /> <Component /> |
| 创建 React 应用 | npx create-react-app my-app |