动手做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.
已筛到你正在学的《Cab Booking》。想看全部就点上面的「全部」。Filtered to Cab Booking — the course you are on. Use “All” above to see everything.
练习Exercises
筛出 3 个练习(共 148 个)。Showing 3 of 148.- createContext() 不传默认值 —— 这样没套 Provider 时是 undefined,守卫才抓得住createContext() takes no default value — that way it is undefined with no Provider around, which is what the guard catches
- 两个 state:bookedCabDetails 初始 null、rideHistory 初始 []Two states: bookedCabDetails starts null, rideHistory starts []
- updateBookedCabDetails 同时改两个 state,历史用不可变更新(展开运算符),不许 pushupdateBookedCabDetails changes both states, and the history update is immutable (spread), never push
- useCabContext 里有 if 守卫 + throw,错误信息要出现 CabProvideruseCabContext has an if guard plus a throw, and the message mentions CabProvider
- 命名导出 CabProvider 和 useCabContextNamed exports for CabProvider and useCabContext
看答案之前,先确认你已经自己动手写过一遍。看懂别人的答案和自己写出来,是两种能力。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.
alt 和 type="button"。You only get the props signature. Write the five testids yourself, and do not forget alt and type="button".- 五个 data-testid 一个不少:cab-card-img / -name / -type / -price / -select-buttonAll five data-testid values: cab-card-img / -name / -type / -price / -select-button
- img 要有 alt(测试不查,但没有 alt 是真实的可访问性缺陷)The img needs an alt (the tests do not check it, but a missing alt is a real accessibility defect)
- 按钮写 type="button" —— 不写的话在 <form> 里会变成提交按钮The button needs type="button" — without it, inside a <form> it becomes a submit button
- onClick 里包一层箭头函数把 cab 传进去,不是直接传 onSelectCabWrap the onClick in an arrow function that passes cab in; do not pass onSelectCab directly
- 价格前面要有 $ —— 历史列表的断言查的是 "$20"The price needs a $ in front — the history assertion looks for "$20"
看答案之前,先确认你已经自己动手写过一遍。看懂别人的答案和自己写出来,是两种能力。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.
- 从 useCabContext() 里读 rideHistoryRead rideHistory out of useCabContext()
- 取最新三条并让最新的排在最上面(slice(-3).reverse() 或等价写法)Take the three newest and put the newest at the top (slice(-3).reverse() or an equivalent)
- 不许在 rideHistory 上直接调 reverse / sort —— 那会原地改 stateNever call reverse or sort on rideHistory directly — that changes the state in place
- 每条记录一个 <li data-testid="history-cabs">,里面有车名和 $价格One <li data-testid="history-cabs"> per record, holding the cab name and the $price
- 空历史显示 <p data-testid="no-ride-title">No ride history yet.</p>,且此时不渲染列表An empty history shows <p data-testid="no-ride-title">No ride history yet.</p> and renders no list
- key 不能只用 ride.id —— 同一辆车可以被订两次The key cannot be ride.id alone — the same cab can be booked twice
看答案之前,先确认你已经自己动手写过一遍。看懂别人的答案和自己写出来,是两种能力。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.