DrillLab
练习Practice

动手做Get your hands on it

练习跟着课文走 —— 每节课尾都有本课的练习。这一页是全部练习的总库,想集中刷题的时候来。 每个练习都写清了它来自哪一节,卡住了就回去看那一节。Practice follows the lessons — every lesson ends with the exercises for that lesson. This page is the whole library, for when you want to drill in one sitting. Each exercise names the lesson it came from, so you can go back when you stall.

0 / 148个做对过you got right

已筛到你正在学的《React 考试》。想看全部就点上面的「全部」。Filtered to React exam — the course you are on. Use “All” above to see everything.

练习Exercises

筛出 54 个练习(共 148 个) · 第 2 / 5 页。Showing 54 of 148 · page 2 / 5.
来自From 派生数据与状态提升:什么不该做成 stateValues you can compute, and lifting state up: what should not be state · React 考试React exam
L1认出来Spot it哪个应该做成 stateWhich one should become state

假设要给 Notes Manager 加一个「显示当前有几条笔记」的文字。 这个数字应该怎么实现?

Say you have to add a line to Notes Manager that shows how many notes there are right now. How should that number be produced?

先选一个选项Pick an option first
来自From 派生数据与状态提升:什么不该做成 stateValues you can compute, and lifting state up: what should not be state · React 考试React exam
L1认出来Spot it这个 state 该住哪Where should this state live

假设要加一个搜索框(在 NoteForm 上方,属于 NoteManager 的直接子元素), 输入关键词后表格只显示匹配的笔记。 搜索关键词这个 state 该放在哪?

Say you add a search box above NoteForm, as a direct child of NoteManager. Once a keyword is typed, the table shows only the notes that match. Where should the state holding that keyword go?

先选一个选项Pick an option first
来自From 派生数据与状态提升:什么不该做成 stateValues you can compute, and lifting state up: what should not be state · React 考试React exam
L3写整块Write a block写出派生数据与按钮文字Write the computed value and the button text

补出 isFormInvalid 和按钮的两处动态部分。 注意:只输入空格也应该算无效。

Fill in isFormInvalid and the two changing parts of the button. Note: spaces only should also count as invalid.

要求Requirements
  • isFormInvalid 是一个普通 const,不许用 useStateisFormInvalid is a plain const; useState is not allowed
  • 只输入空格也要判定为无效(用 trim)Spaces only must also count as invalid (use trim)
  • 按钮在表单无效时 disabledThe button is disabled while the form is invalid
  • 按钮文字:noteToEdit 存在时是 Update,否则是 Add(大小写必须一致)Button text: Update when noteToEdit exists, otherwise Add (the capitals must match)
  • 不许改动 data-testidDo not change any data-testid
TSXsrc/components/NoteForm/index.tsx
This check is textual: it looks for the right constructs, it does not run your code
提示Hints共 4 级,已看 0 级4 levels, 0 opened
先自己想两分钟。想不出来再点右上角 —— 提示是一级一级放的,不会一次给完。Think for two minutes first. Then use the button above — hints come one level at a time, never all at once.

看答案之前,先确认你已经自己动手写过一遍。看懂别人的答案和自己写出来,是两种能力。Before you open this, make sure you have written it yourself once. Following someone else's answer and producing your own are two different skills.

来自From 先读题:三个任务、一条硬约束、四个测试Read the question first: three tasks, one rule you must not break, four tests · React 考试React exam
L1认出来Spot it哪一处改动会让测试挂掉Which change makes a test fail

README 只说了「不得修改任何 data-testid」。 下面哪些改动也会让现有测试失败?(多选)

The README says only that no data-testid may be changed. Which of the changes below also break the existing tests? (more than one)

这题是多选。More than one answer is correct.

先选一个选项Pick an option first
来自From 先读题:三个任务、一条硬约束、四个测试Read the question first: three tasks, one rule you must not break, four tests · React 考试React exam
L1认出来Spot it题目没写但测试在查的是哪一条The requirement the task never states but a test checks

README 的三个 Task 里没提到某个要求, 但四个测试里有一条专门在查它。是哪个?

One requirement is never mentioned in the three Tasks of the README, yet one of the four tests checks exactly that. Which one is it?

先选一个选项Pick an option first
来自From 先读题:三个任务、一条硬约束、四个测试Read the question first: three tasks, one rule you must not break, four tests · React 考试React exam
L1排顺序Order it把上手顺序排对Put the starting steps in order

拿到这个项目,最合理的动作顺序是什么?

You just received this project. What is the most sensible order to work in?

1写代码:三个 handler 逐个实现Write the code: implement the three handlers one at a time
2npm install,然后 npx vitest run 拿到基线npm install, then npx vitest run to get a baseline
3读 NoteForm / NoteTable / NoteItem,确认它们已经完整、不用改Read NoteForm / NoteTable / NoteItem and confirm they are already complete and need no change
4读 README + 读测试文件,抄下所有验收标准Read the README and the test file, and write down every acceptance criterion
5npx vitest run 验证,再 npm run dev 手动点一遍Verify with npx vitest run, then npm run dev and click through it by hand
6读 types/Note.ts,确认数据形状和 id 的类型Read types/Note.ts to confirm the shape of the data and the type of id
来自From Task 1 · Add:提交表单,新笔记进入表格Task 1 · Add: submit the form and the new note appears in the table · React 考试React exam
L2填空Fill the blanks补全新增逻辑Fill in the add logic

两个空。想清楚「旧的要不要留」和「用哪种更新形式」。

Two blanks. Decide whether the old notes have to stay, and which form of update to use.

TSXsrc/components/NoteManager/index.tsx2 个空2 blanks
1const handleSubmitNote = (submittedNote: Note) => {
2 if (noteToEdit) {
3 // Task 3
4 } else {
5 setNotes(() => [, submittedNote]);
6 }
7};
把 2 个空都填上才能检查(还差 2 个)Fill all 2 blanks to check (2 to go)
来自From Task 1 · Add:提交表单,新笔记进入表格Task 1 · Add: submit the form and the new note appears in the table · React 考试React exam
L3写整块Write a block不看答案,自己写出 Task 1Write Task 1 yourself, without looking at the answer

只给你函数签名和要求。自己写完整实现。 写完点「检查我的代码」,它会用文本规则检查你有没有踩坑。

You get the function signature and the requirements. Write the whole implementation yourself. When you are done, use the check button: it applies text rules to see whether you fell into a known trap.

要求Requirements
  • 把 submittedNote 追加到 notes 的末尾Append submittedNote to the end of notes
  • 原有的笔记全部保留Keep every note that was already there
  • 必须用函数式更新 setNotes(prev => ...)Use a functional update: setNotes(prev => ...)
  • 不许用 push / splice / unshift 修改原数组Do not change the original array with push / splice / unshift
  • 留出 if (noteToEdit) 分支的位置(Task 3 会填)Leave room for the if (noteToEdit) branch (Task 3 fills it in)
TSXsrc/components/NoteManager/index.tsx
This check is textual: it looks for the right constructs, it does not run your code
提示Hints共 4 级,已看 0 级4 levels, 0 opened
先自己想两分钟。想不出来再点右上角 —— 提示是一级一级放的,不会一次给完。Think for two minutes first. Then use the button above — hints come one level at a time, never all at once.

看答案之前,先确认你已经自己动手写过一遍。看懂别人的答案和自己写出来,是两种能力。Before you open this, make sure you have written it yourself once. Following someone else's answer and producing your own are two different skills.

来自From Task 2 · Delete:点 Delete,该行按 id 被移除Task 2 · Delete: click Delete and that one row is removed by id · React 考试React exam
L2填空Fill the blanks补全删除逻辑Fill in the delete logic

三个空。第三个空是这道题唯一会绕人的地方。

Three blanks. The third one is the only part that trips people up.

TSXsrc/components/NoteManager/index.tsx3 个空3 blanks
1const handleDelete = (id: number) => {
2 setNotes((prev) => prev.((note) => note. id));
3};
把 3 个空都填上才能检查(还差 3 个)Fill all 3 blanks to check (3 to go)
来自From Task 2 · Delete:点 Delete,该行按 id 被移除Task 2 · Delete: click Delete and that one row is removed by id · React 考试React exam
L3写整块Write a block不看答案,自己写出 Task 2Write Task 2 yourself, without looking at the answer

一行代码的题。但要一次写对,不许用 push / splice。

One line of code. But get it right the first time, and without push or splice.

要求Requirements
  • 按 id 移除对应的那一条Remove the matching note by id
  • 其余笔记全部保留,顺序不变Keep every other note, in the same order
  • 必须用函数式更新Use a functional update
  • 不许修改原数组(不许用 splice)Do not change the original array (no splice)
  • 不许按 title 或下标比较Do not compare by title or by index
TSXsrc/components/NoteManager/index.tsx
This check is textual: it looks for the right constructs, it does not run your code
提示Hints共 4 级,已看 0 级4 levels, 0 opened
先自己想两分钟。想不出来再点右上角 —— 提示是一级一级放的,不会一次给完。Think for two minutes first. Then use the button above — hints come one level at a time, never all at once.

看答案之前,先确认你已经自己动手写过一遍。看懂别人的答案和自己写出来,是两种能力。Before you open this, make sure you have written it yourself once. Following someone else's answer and producing your own are two different skills.

来自From Task 2 · Delete:点 Delete,该行按 id 被移除Task 2 · Delete: click Delete and that one row is removed by id · React 考试React exam
L2Debug LabDebug LabDebug Lab · 删一条,同名的全没了Debug Lab · delete one note and every note with the same title goes too

测试全过,但手动测试时发现:三条标题相同的笔记, 点其中一条的 Delete,三条一起消失。

Every test passes, but a manual check shows this: with three notes that share a title, clicking Delete on one of them makes all three disappear.

第 1 步 · 先看现象和代码,别急着改Step 1 · read the symptom and the code before you touch anything
# 测试:4 passed (4) ← 测试全过! # 手动复现步骤: # 1. 添加 "会议记录 / 内容1" # 2. 添加 "会议记录 / 内容2" # 3. 添加 "会议记录 / 内容3" # 4. 点第 2 行的 Delete # 期望:只剩「内容1」「内容3」 # 实际:表格全空# Tests: 4 passed (4) ← every test passes! # Manual repro steps: # 1. Add "会议记录 / 内容1" # 2. Add "会议记录 / 内容2" # 3. Add "会议记录 / 内容3" # 4. Click Delete on the second row # Expected: only 内容1 and 内容3 are left # Actual: the table is empty
TSX有问题的 handleDeleteThe handleDelete with the bug示意Illustrative
1const handleDelete = (id: number) => {
2 const target = notes.find((n) => n.id === id);
3 setNotes((prev) => prev.filter((note) => note.title !== target?.title));
4};
第 2 步 · 这是什么类型的错误Step 2 · what kind of error is this
来自From Task 3 · Edit:回填、改文字、就地更新、退出编辑Task 3 · Edit: refill the form, change the button text, update the row where it is, leave edit mode · React 考试React exam
L2填空Fill the blanks补全编辑逻辑的四个关键位置Fill in the four key spots of the edit logic

四个空横跨两个函数。第 4 个空是最容易漏的那一行 —— 漏了它测试照样能过,但行为明显不对。

Four blanks across two functions. The fourth is the line people forget most often — without it the tests still pass, but the behavior is clearly wrong.

TSXsrc/components/NoteManager/index.tsx4 个空4 blanks
1const handleSubmitNote = (submittedNote: Note) => {
2 if (noteToEdit) {
3 setNotes((prev) =>
4 prev.((note) =>
5 note.id submittedNote.id ? : note,
6 ),
7 );
8 ;
9 } else {
10 setNotes((prev) => [...prev, submittedNote]);
11 }
12};
13
14const handleEdit = (note: Note) => {
15 setNoteToEdit(note);
16};
把 4 个空都填上才能检查(还差 4 个)Fill all 4 blanks to check (4 to go)