Skip to content

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 逻辑 的封装体。

对比传统开发

html
<!-- 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。

javascript
// 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 的等效写法:

javascript
// ❌ 不用 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 基本结构

html
<!-- 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>
javascript
// 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 元素:

javascript
// ❌ 两个元素 → 报错
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 表达式

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 语句

javascript
// ✅ 表达式 — 会产生一个值
{2 + 3}                    // → 5
{Math.floor(Math.random() * 10)}  // → 随机数
{name.toUpperCase()}       // → "ANGELA"

// ❌ 语句 — 不能放在 {} 中
{if (name === "Angela") return 7}  // 报错!

3.3 ES6 模板字面量

javascript
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 动态年份实战

javascript
const year = new Date().getFullYear();

ReactDOM.render(
  <p>Copyright ⓒ {year}</p>,
  document.getElementById("root")
);
// 输出:Copyright ⓒ 2026(自动更新)

常见错误

javascript
// ❌ 忘记加 () — 传入的是函数引用,不是返回值
{new Date().getFullYear}  // → 报错:函数不是有效的 React 子元素

// ✅ 加上 () 调用方法
{new Date().getFullYear()} // → 2026

四、JSX 属性与样式

4.1 属性命名规则

JSX 属性使用 camelCase(驼峰),而非 HTML 的全小写:

HTML 属性JSX 属性
classclassName
contenteditablecontentEditable
spellcheckspellCheck
tabindextabIndex
forhtmlFor
jsx
// ❌ HTML 风格 — 会产生警告
<h1 class="heading" contenteditable="true">Hello</h1>

// ✅ JSX 风格 — 正确
<h1 className="heading" contentEditable={true} spellCheck={false}>Hello</h1>

4.2 className 样式(推荐)

css
/* styles.css */
.heading {
  color: red;
  font-size: 24px;
  font-weight: bold;
}

.food-img {
  width: 100px;
  height: 100px;
}
jsx
<h1 className="heading">My Favorite Foods</h1>
<img className="food-img" src="..." alt="bacon" />

4.3 内联样式(JavaScript 对象)

内联样式的值必须是 JavaScript 对象,不是字符串:

jsx
// ❌ HTML 字符串形式 — 报错
<h1 style="color: red">Hello</h1>

// ✅ JavaScript 对象形式(双花括号)
<h1 style={ {color: "red"} }>Hello</h1>
//    ↑外层{} = JSX注入   ↑内层{} = JS对象

4.4 CSS 属性名转换

CSS 属性也使用 camelCase,值为 字符串,分隔用 逗号(非分号):

javascript
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 内联样式的使用场景

内联样式的最大优势 = 动态更新

javascript
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 中没有子元素的标签 必须 自闭合:

jsx
// ❌ HTML 可以不闭合 — JSX 不行
<img src="..." alt="photo">  // 报错:Unterminated JSX

// ✅ 必须自闭合
<img src="..." alt="photo" />
<br />
<hr />
<input />

五、React 组件

5.1 函数组件

组件本质是一个 返回 JSX 的函数,名称使用 PascalCase

javascript
// Heading.jsx
import React from "react";

function Heading() {
  return <h1>My Favorite Foods</h1>;
}

export default Heading;

5.2 使用组件

jsx
// 自定义组件 → 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 — 只负责渲染:

javascript
import React from "react";
import ReactDOM from "react-dom";
import App from "./components/App";

ReactDOM.render(<App />, document.getElementById("root"));

App.jsx — 组件树根节点:

javascript
import React from "react";
import Heading from "./Heading";
import List from "./List";

function App() {
  return (
    <div>
      <Heading />
      <List />
    </div>
  );
}

export default App;

Heading.jsx — 独立组件:

javascript
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)

每个文件只能有 一个 默认导出,导入时 可以任意命名

javascript
// 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)

一个文件可以有 多个 命名导出,导入时 名称必须匹配

javascript
// 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 通配符导入

javascript
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 前提条件

bash
# 检查 Node 版本(需要 12+)
node --version

7.2 创建 React 应用

bash
npx create-react-app my-app
# npx = npm 的包运行器,无需全局安装

cd my-app
npm start
# → 自动打开 http://localhost:3000

7.3 项目清理

创建后删除不必要的模板文件,保留核心结构:

my-app/
├── public/
│   └── index.html       # 只保留这一个
└── src/
    └── index.js         # 只保留这一个

清理后的 index.html:

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:

javascript
import React from "react";
import ReactDOM from "react-dom";

ReactDOM.render(<h1>Hello World!</h1>, document.getElementById("root"));

7.4 文件命名约定

文件命名说明
入口文件index.js保持 .js 扩展名
组件文件Heading.jsxHeading.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

← 返回 Web 开发研究