R01第 1 / 1 课时未开始内容版本 1.0.0 · 核验于 2026-10-26

React 与组件思维

React 与组件思维 · 阅读后完成下方实验与检查题,再用「标记完成」记录进度。

学习目标

这一课帮你建立 React 最核心的心智模型:界面由组件拼成,组件是「输入 → 界面描述 → 交互」的闭环。读完你能把一块完整的页面按职责拆成组件,并说清每个组件各自管什么、互相怎么衔接。

问题场景

假设学习工作台的首页是这样写出来的:一个 Home 函数返回了三百多行 JSX——顶部导航、课程卡片、学习统计、页脚全在里面。现在产品要求「课程卡片上加一个收藏按钮」,你从三百行里翻出卡片那 40 行,改完又发现统计区也想用同样的卡片,只能复制粘贴一份。改一处、抄一处,错误就是这么来的。

核心解释

React 组件本质上是一个函数:接收输入,返回一段界面描述(JSX)。拆组件的依据不是「代码行数」,而是职责——一个组件只应该因为一个原因被修改。课程卡片因为需求变化而改,页脚不会跟着改,它们就不该待在同一个函数里。

每个组件内部都有一个闭环:

  1. 输入:从外部拿到的数据(props)和自己私有的状态(state);
  2. 展示:根据输入返回 JSX,描述「这个状态下界面长什么样」;
  3. 交互:用事件处理(如 onClick)响应用户操作,更新自己的状态——状态一变,React 重新调用这个函数,界面随之更新。

用代码表达这个闭环,就三样东西:

function FavButton() {
  const [faved, setFaved] = useState(false); // 输入之外自己的状态
  return (
    <button onClick={() => setFaved(!faved)}> {/* 交互:改状态 */}
      {faved ? "已收藏" : "收藏"}            {/* 展示:由状态推导 */}
    </button>
  );
}

拆分时先找「重复出现的结构」(三张课程卡片就是同一个组件用三次),再找「独立的改动原因」(导航、内容、页脚分开)。组件名必须大写开头,React 靠这个区分自定义组件和 <div> 这类原生标签。

function CourseCard({ course }) {
  return (
    <div className="card">
      <h3>{course.title}</h3>
      <p>{course.summary}</p>
    </div>
  );
}

function Home() {
  return (
    <main>
      <CourseCard course={courses[0]} />
      <CourseCard course={courses[1]} />
    </main>
  );
}

示例拆解

实验区把一个迷你工作台拆成了三个组件,关键点如下:

  • Header 只管标题区,无输入、无状态——最简单的一类组件;
  • CourseCard 接收一个 course 对象作为输入,内部用 useState 记录「是否已收藏」,点击按钮翻转状态,界面上的标记跟着变;
  • App 负责把组件按页面结构组合起来,同一份 CourseCard 传三份不同数据,就是三张不同的卡片。

验证方式:在实验区点任意卡片的「收藏」按钮,只有那张卡变化——因为收藏状态在各组件内部独立,互不干扰。这正是拆组件换来的隔离性。

动手任务

打开本课实验区,完成三个小改动:

  1. 给 CourseCard 增加一个显示课时数的区域,数据来自 course.lessons(先在数据里补上这个字段)。
  2. 再往页面里加一张第四门课的卡片,体会「复用」和「复制粘贴」的差别。
  3. 把卡片上的收藏文字改成「收藏 / 已收藏」两种状态文案,观察你只需要改 CourseCard 一个组件。

常见错误

  • 组件名小写开头:写成 function courseCard(),JSX 里的 <courseCard /> 会被 React 当成未知的 HTML 标签,页面空白且不报明显错误。
  • 把整页塞进一个组件:所有状态都堆在一起,任何小改动都可能牵动整页;先按「独立改动原因」切分。
  • 拆得过细:一个 <p> 都包成组件,组合成本超过收益;小组件要在「真的会被复用或独立变化」时才拆。
  • 在组件函数内部再定义组件:每次渲染都会创建新的组件类型,内部状态会被整个丢掉;组件要么定义在顶层,要么通过 props 传递。

检查与复盘

完成下方检查题确认理解。自查清单:

  • 拿到一块界面,能先说出「哪几块会因为不同原因被改动」,再动手拆
  • 能对任意一个组件说出它的输入是什么、状态是什么、交互改了哪个状态
  • 知道组件名为什么必须大写,以及嵌套定义组件会出什么问题

参考资料

动手实验
动手实验
预览
点击「运行」在隔离沙箱中预览
检查题共 2 题,提交后立即显示解析
答案由服务端判定;答错的题会自动进入复习计划。
Q1单选简单

关于 React 组件,下列说法正确的是?

Q2读代码简单

阅读代码(React 18+)。页面渲染了两个 StatusLight。点击第一个灯把它变成「开」之后,第二个灯显示什么?

function StatusLight() {
  const [on, setOn] = useState(false);
  return (
    <button onClick={() => setOn(!on)}>
      {on ? '开' : '关'}
    </button>
  );
}

export default function App() {
  return (
    <>
      <StatusLight />
      <StatusLight />
    </>
  );
}

读完这一课了?

标记完成后,工作台会安排接下来的学习。

Command Palette

Search for a command to run...