大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
React
这一课你将能做到
- 用函数组件 + Hooks 写 React 组件
- 理解 JSX、Props、State 的分工
- 用
useEffect调用后端 API 渲染列表
为什么要学
原生 JavaScript 操作 DOM 写页面,代码一多就乱:选中元素、改内容、绑事件、更新状态,全混在一起。React 用「组件」把页面拆成独立小块,每块管自己的数据和渲染,代码清晰、好维护。
人话:React 是「乐高积木」,把页面拆成可复用的组件,拼起来就是完整应用。
先建立图像
// 组件 = 函数,返回 JSX(HTML 的 JS 写法)
function CourseCard({ title, desc }) {
return (
<div className="card">
<h3>{title}</h3>
<p>{desc}</p>
</div>
);
}
// 使用组件
function App() {
return (
<div>
<CourseCard title="HTML" desc="网页骨架" />
<CourseCard title="CSS" desc="网页皮肤" />
</div>
);
}
浏览器渲染后:
<div>
<div class="card">
<h3>HTML</h3>
<p>网页骨架</p>
</div>
<div class="card">
<h3>CSS</h3>
<p>网页皮肤</p>
</div>
</div>
跟着做
步骤 1:创建 React 项目(Vite)
npm create vite@latest my-app -- --template react
cd my-app
npm install
npm run dev
打开 http://localhost:5173,看到默认页面。
步骤 2:第一个组件
// src/components/Hello.jsx
function Hello({ name }) {
return <h1>Hello, {name}!</h1>;
}
export default Hello;
// src/App.jsx
import Hello from './components/Hello';
function App() {
return (
<div>
<Hello name="CodeRoadMap" />
<Hello name="React" />
</div>
);
}
export default App;
步骤 3:State 与事件
import { useState } from 'react';
function Counter() {
// count 是状态,setCount 是更新函数
const [count, setCount] = useState(0);
return (
<div>
<p>点击了 {count} 次</p>
<button onClick={() => setCount(count + 1)}>
+1
</button>
<button onClick={() => setCount(0)}>
重置
</button>
</div>
);
}
点击按钮,页面自动更新——不需要手动操作 DOM。
步骤 4:列表渲染
function CourseList({ courses }) {
return (
<ul>
{courses.map(course => (
<li key={course.id}>
<strong>{course.title}</strong>
<span>{course.desc}</span>
</li>
))}
</ul>
);
}
// 使用
const data = [
{ id: 1, title: 'HTML', desc: '骨架' },
{ id: 2, title: 'CSS', desc: '皮肤' },
{ id: 3, title: 'JS', desc: '肌肉' },
];
<CourseList courses={data} />
map 遍历数组,key 帮助 React 识别元素变化。
步骤 5:useEffect 调用后端 API
import { useState, useEffect } from 'react';
function CourseList() {
const [courses, setCourses] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('/api/courses')
.then(res => res.json())
.then(data => {
setCourses(data);
setLoading(false);
})
.catch(err => {
console.error('加载失败:', err);
setLoading(false);
});
}, []); // 空数组 = 只在组件挂载时执行一次
if (loading) return <p>加载中...</p>;
return (
<ul>
{courses.map(c => (
<li key={c.id}>{c.title}</li>
))}
</ul>
);
}
步骤 6:条件渲染
function Dashboard({ isLoggedIn, user }) {
if (!isLoggedIn) {
return <p>请先登录</p>;
}
return (
<div>
<h2>欢迎,{user.name}</h2>
{user.isVip && <span>VIP 标识</span>}
</div>
);
}
步骤 7:表单处理
function LoginForm() {
const [form, setForm] = useState({ username: '', password: '' });
const handleChange = (e) => {
setForm({
...form,
[e.target.name]: e.target.value
});
};
const handleSubmit = (e) => {
e.preventDefault();
fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(form)
})
.then(res => res.json())
.then(data => {
if (data.code === 0) {
localStorage.setItem('token', data.data.token);
alert('登录成功');
} else {
alert(data.msg);
}
});
};
return (
<form onSubmit={handleSubmit}>
<input
name="username"
value={form.username}
onChange={handleChange}
placeholder="用户名"
/>
<input
name="password"
type="password"
value={form.password}
onChange={handleChange}
placeholder="密码"
/>
<button type="submit">登录</button>
</form>
);
}
讲清楚要点
- 组件是独立单元:每个组件管自己的数据和渲染,通过 Props 接收外部数据。
- JSX 是语法糖:
<div>编译成React.createElement('div'),最终渲染成真实 DOM。 - State 驱动视图:数据变 → 视图自动更新,不需要手动
document.querySelector。 - Hooks 是函数组件的能力:
useState管数据,useEffect管副作用(请求、定时器)。 - Key 帮助 React 识别元素:列表渲染必须加
key,否则性能差、状态错乱。
你可能会懵的地方
-
React 和 Vue 选哪个? React 生态更大、灵活;Vue 上手更快、文档友好。中小项目都行,看团队熟悉度。
-
为什么组件名要大写? 小写会被当成 HTML 标签(
<div>),大写才是组件(<CourseCard />)。 -
useEffect 的依赖数组?
[]= 只执行一次;[count]= count 变化时执行;不传 = 每次渲染都执行(慎用)。 -
State 更新是同步还是异步? 异步。
setCount(count + 1)后立刻console.log(count)还是旧值。用函数式更新:setCount(prev => prev + 1)。 -
Props 能修改吗? 不能。Props 是父组件传的,子组件只读。要改数据,通知父组件改。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
class 代替 className | JSX 中 class 是保留字 | 用 className |
直接修改 state:count++ | React 检测不到变化 | setCount(count + 1) |
列表不加 key | 性能差、状态错乱 | 每个子元素加唯一 key |
useEffect 里写死循环请求 | 依赖数组为空但请求依赖 props | 把依赖项加进数组 |
在渲染函数里调用 setState | 无限循环渲染 | 在事件或 useEffect 里调用 |
卡点急救
- 页面空白:检查控制台报错,通常是组件名未大写、导入路径错误、或 JSX 语法错误。
- State 不更新:确认用
setState而非直接赋值;检查是否修改了引用类型的内部属性(需返回新对象)。 - useEffect 执行两次:React 18 严格模式下开发环境会双调用,生产环境正常。不是 bug。
面试常问
-
虚拟 DOM 是什么? JS 对象模拟真实 DOM,数据变化时先对比虚拟 DOM,算出最小差异,再批量更新真实 DOM。减少直接操作 DOM 的开销。
-
类组件和函数组件区别? 类组件用
this.state、this.setState、生命周期方法;函数组件用 Hooks。现代 React 推荐函数组件。 -
useEffect 和 useLayoutEffect 区别?
useEffect异步执行,不阻塞渲染;useLayoutEffect同步执行,在浏览器绘制前完成。一般用useEffect,需要测量 DOM 时用useLayoutEffect。 -
Context 和 Redux 选哪个? Context 适合低频更新的全局数据(主题、语言);Redux 适合复杂状态管理(购物车、表单)。小项目 Context 足够。
自测三问
useState的返回值是什么?useEffect的依赖数组传[]和不传的区别?- 为什么列表渲染需要
key?
小结一句话
React 用组件拆分页面,State 驱动视图更新,Hooks 让函数组件拥有完整能力。
延伸
- React 官方文档
- 下一课:Node.js 用 JavaScript 写后端。