动手做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.
练习Exercises
筛出 148 个练习 · 第 6 / 13 页。Showing 148 · page 6 / 13.给深层评论加回复,console.log 打出来的树里 新回复确实在,但界面没变化。控制台干净。
You add a reply to a deep comment. The tree printed by console.log really does contain the new reply, but the screen does not change. The console is clean.
四个空。第 3 个是最容易漏的那一步,第 4 个决定「忘了套 Provider」 时报错清不清楚。
Four blanks. The third is the step people miss most. The fourth decides how clear the error is when somebody forgets to wrap things in the Provider.
类型已给好。写出 context、Provider、自定义 hook 三部分。 检查器会查记忆化、函数式更新和守卫。
The types are given. Write all three parts: the context, the Provider, and the custom hook. The checker looks for the memoization, the updater form and the guard.
- theme 初始为 'light'theme starts as 'light'
- toggleTheme 在 light / dark 之间翻转,必须用函数式更新toggleTheme flips between light and dark, using the updater form
- context value 要记忆化,theme 不变时不产生新对象The context value has to be memoized, so no new object appears while theme is unchanged
- toggleTheme 引用要稳定(theme 变了它也不变)The reference of toggleTheme has to be stable, unchanged even when theme changes
- 没套 Provider 就用 useTheme() 时抛出一句能看懂的错误Calling useTheme() with no Provider above it throws a message a person can read
- 不许把 theme 存到组件外的全局变量里Do not keep theme in a global variable outside the component
看答案之前,先确认你已经自己动手写过一遍。看懂别人的答案和自己写出来,是两种能力。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.
按钮好好的,卡片一渲染就整页白屏。这是真实报错。
The button is fine, and the moment the card renders the whole page goes blank. This is the real error.
新建了组件之后启动开发服务器,Vite 直接报错,页面白屏。
You add a new component, start the dev server, and Vite reports an error right away. The page is blank.
重构时把父组件传的 prop 名改了,子组件忘了跟着改。 页面能显示,但点 Delete 直接崩。
During a refactor the prop name passed by the parent was changed, and the child component was not changed to match. The page still renders, but clicking Delete crashes it.
代码看起来完全正确,手动点也没问题,但两个测试挂了。
The code looks entirely correct and clicking through it by hand works, but two tests fail.
这一题不告诉你是哪一类。控制台干净,console.log 显示数据是对的。 自己分诊。
This one does not tell you which category it is. The console is clean, and console.log shows the data is correct. Sort it yourself.
空目录开始,建出一个 React + TypeScript + Vite 项目, 实现 Notes Manager 的增删改,让下面那四个测试全过。不要打开 react-notes-app 参考。
Starting from an empty directory, build a React + TypeScript + Vite project. Implement add, delete and edit in Notes Manager, and make all four tests below pass. Do not open react-notes-app to look.
- 页面上方是表单:Title 输入框、Content 文本域、一个提交按钮The form sits at the top of the page: a Title input, a Content textarea, and one submit button
- 页面下方是表格:表头 Title / Content / Edit / Delete,每条笔记一行The table sits below: the header is Title / Content / Edit / Delete, with one row per note
- 两个输入框都必须是受控的(value + onChange)Both inputs must be controlled (value + onChange)
- 标题或内容为空(含只有空格)时,提交按钮 disabledWhen the title or the content is empty (including only spaces), the submit button is disabled
- Task 1 Add:提交后新笔记出现在表格末尾,原有的都还在Task 1 Add: after submit the new note appears at the end of the table, and every existing note is still there
- Task 2 Delete:点某行的 Delete,该行按 id 被移除(同名笔记只删对的那条)Task 2 Delete: clicking Delete on a row removes that row by id (with notes of the same name, only the right one goes)
- Task 3 Edit:点某行的 Edit → 内容回填进表单、按钮文字变成 UpdateTask 3 Edit: clicking Edit on a row fills its content back into the form, and the button text becomes Update
- Task 3 提交后:该笔记在原位置被更新(顺序不变),然后退出编辑模式(表单清空、按钮回到 Add)Task 3 after submit: the note is updated in place (the order does not change), and edit mode ends (the form clears, the button goes back to Add)
- 必须带上这些 data-testid:note-manager / note-form / form-input / form-textarea / form-submit-button / notes-listThese data-testid values are required: note-manager / note-form / form-input / form-textarea / form-submit-button / notes-list
- 行内按钮的文字必须正好是 Edit 和 DeleteThe text on the row buttons must be exactly Edit and Delete
- Note 的类型是 { id: number; title: string; content: string }The type of Note is { id: number; title: string; content: string }
这一关的意义就在于「没有答案也能写出来」。请确认你已经在本机建好文件、跑过验证命令,再打开参考答案对照。The whole point of this level is writing it with no answer in front of you. Create the files on your machine and run the verification commands first, then come back and compare.
只给类型定义和三条要求。自己写出 runTasks, 并自己写一个验证台来证明它对。
You get only the type definitions and three requirements. Write runTasks yourself, and write your own check harness to show that it is right.
- runTasks(tasks, limit) 接收一个「函数数组」,每个函数被调用后返回 PromiserunTasks(tasks, limit) takes an array of functions, and each function returns a Promise when it is called
- 同一时刻最多 limit 个任务在运行;某个结束后立刻启动下一个At most limit tasks run at the same time; as soon as one finishes, start the next
- 任何任务失败都不能让 runTasks 抛错No failing task may make runTasks throw
- 返回数组顺序必须与 tasks 一致The order of the returned array must match tasks
- 成功写 { status: "fulfilled", value },失败写 { status: "rejected", reason }On success write { status: "fulfilled", value }; on failure write { status: "rejected", reason }
- 自己写一个 demo:6 个任务(其中至少 1 个 reject)、limit = 2,打印实时并发数与最终结果Write your own demo: 6 tasks (at least 1 of which rejects), limit = 2, printing how many run at each moment and the final results
这一关的意义就在于「没有答案也能写出来」。请确认你已经在本机建好文件、跑过验证命令,再打开参考答案对照。The whole point of this level is writing it with no answer in front of you. Create the files on your machine and run the verification commands first, then come back and compare.
看真实 schema 里的 type Order。 下面哪些字段的类型是标量(不能再往下展开)?(多选)
Look at type Order in the real schema. Which of these fields have a scalar type — one that cannot be expanded any further? (Select all that apply.)
graphql-federation-practice/node-subgraph/src/schema.graphql这题是多选。More than one answer is correct.
真实 schema 里 createOrder 放在type Mutation 下。如果把它挪到type Query 下会怎样?
In the real schema, createOrder sits under type Mutation. What happens if you move it under type Query?