React / 闯关模式
React 入门篇:组件 JSX Props State
用 React 19、TypeScript、组件、JSX、Props 和 State 写用户管理页的第一版。
一句话:React 入门先抓住一件事,页面是由组件拼出来的,组件根据 props 和 state 渲染界面。
第 2 篇 / 共 12 篇。
本篇学完你会:用 React 19 + TypeScript 写出用户管理页面的静态列表、拆组件、传 props、使用 state 控制选中和搜索输入。
1. React 是什么
React 是一个用 JavaScript/TypeScript 写用户界面的库。你可以把它想成“积木说明书”:每个组件是一块积木,整个页面就是积木组合。
React 最重要的公式是:
UI = Component(props, state)意思是:组件拿到外部传入的 props 和自己内部的 state,然后返回界面。

2. 用户管理案例的第一步
我们先做最小版本:
用户管理页
- 顶部标题
- 搜索框
- 用户列表
- 用户状态标签
- 选中用户提示先定义用户类型:
type UserStatus = 'active' | 'disabled';
type User = {
id: number;
name: string;
email: string;
role: 'admin' | 'member';
status: UserStatus;
};准备假数据:
const users: User[] = [
{ id: 1, name: '小明', email: 'ming@example.com', role: 'admin', status: 'active' },
{ id: 2, name: '小红', email: 'hong@example.com', role: 'member', status: 'disabled' }
];3. JSX 是什么
JSX 看起来像 HTML,但它其实是 JavaScript 里的界面表达式。
function PageTitle() {
return <h1>用户管理</h1>;
}大白话:JSX 就是“在 JS 里写页面结构”。
注意两个差异:
| HTML | JSX |
|---|---|
class | className |
onclick | onClick |
比如:
<button className="primary" onClick={() => console.log('新增用户')}>
新增用户
</button>4. 组件是什么
组件就是一个可以复用的 UI 函数。
function UserStatusBadge({ status }: { status: UserStatus }) {
return <span>{status === 'active' ? '正常' : '停用'}</span>;
}它的好处是:状态标签以后哪里都可以用,不用每个页面复制一遍。
用户列表也可以拆成组件。为了让点击某一行能通知父组件,先把 onSelect 也设计进去:
function UserRow({ user, onSelect }: { user: User; onSelect: (id: number) => void }) {
return (
<li>
<strong>{user.name}</strong>
<span>{user.email}</span>
<UserStatusBadge status={user.status} />
<button onClick={() => onSelect(user.id)}>选择</button>
</li>
);
}5. Props 是什么
props 是父组件传给子组件的数据。
function UserList({ users, onSelect }: { users: User[]; onSelect: (id: number) => void }) {
return (
<ul>
{users.map((user) => (
<UserRow key={user.id} user={user} onSelect={onSelect} />
))}
</ul>
);
}这里 UserList 接收 users 和 onSelect,再把每个 user 传给 UserRow。点击某一行时,UserRow 不自己决定选中谁,而是调用父组件传来的 onSelect。
大白话:props 像快递包裹,父组件把数据递给子组件,子组件只负责使用。
6. State 是什么
state 是组件自己记住的数据。比如搜索框当前输入了什么、当前选中了哪个用户。
import { useState } from 'react';
function UserManagementPage() {
const [keyword, setKeyword] = useState('');
const [selectedId, setSelectedId] = useState<number | null>(null);
const filteredUsers = users.filter((user) => user.name.includes(keyword));
return (
<section>
<h1>用户管理</h1>
<input value={keyword} onChange={(event) => setKeyword(event.target.value)} placeholder="搜索用户名" />
<UserList users={filteredUsers} onSelect={setSelectedId} />
<p>当前选中用户 ID:{selectedId ?? '未选择'}</p>
</section>
);
}useState('') 的意思是:请 React 帮我记住一个字符串,初始值是空。
7. 列表渲染和条件渲染
列表用 map:
{users.map((user) => (
<UserRow key={user.id} user={user} />
))}条件用三元表达式或 &&:
{users.length === 0 ? <p>暂无用户</p> : <UserList users={users} />}key 很重要,它告诉 React 每一行是谁。用户列表最适合用稳定的 user.id。
8. 常见错误
| 错误 | 原因 | 修正 |
|---|---|---|
| 直接修改 state | React 不知道你改了 | 用 setState |
| map 没写 key | React 难以追踪列表项 | 用稳定 ID |
| props 里改父组件数据 | 数据方向乱了 | 让父组件传回调 |
JSX 写 class | JSX 属性不同 | 写 className |
如果 state 是数组,不要直接改旧数组:
selectedIds.push(user.id);应该这样:
setSelectedIds((ids) => [...ids, user.id]);9. 下一步怎么学
本篇你已经学到:
| 概念 | 大白话 |
|---|---|
| JSX | 在 JS 里写页面结构 |
| 组件 | 可复用的 UI 函数 |
| Props | 父组件传给子组件的数据 |
| State | 组件自己记住的数据 |
| 列表渲染 | 用数组生成一组 UI |
| 条件渲染 | 根据数据决定显示什么 |