默认只显示问题 —— 先自己在心里答一遍,再展开对答案。答不上来就标「不会」,下次抽认卡会先抽它。Only the question shows by default. Answer it in your head first, then open the answer. Mark the ones you miss; the flashcard round puts those first.
正在读这台浏览器里的标记…Reading your marks from this browser…
标记不是打分,是给下一轮排队Marks are a queue, not a score
标「不会」的题会排到抽认卡最前面,标「会」的进低频池排最后。所以别客气 —— 觉得答得磕磕巴巴就标「模糊」。准备好了就去抽认卡。“No idea” jumps to the front of the next round; “got it” drops to the back. So be honest — if it came out shaky, mark it shaky. Then go run a flashcard round.
In one line: hooks are functions that start with use and give function components state and side effects.
They fix three real pain points — these three are the standard answer:
Reusing logic was hard. All you had were HOCs and render props, and both leave you with wrapper nesting (see #335). A custom hook is flat.
Logic got chopped up by the lifecycle. One coherent “subscribe and unsubscribe” had to be split across two lifecycle methods; useEffect keeps them side by side.
this was too easy to get wrong. Function components have no this.
The common ones:useState, useEffect, useContext, useRef, useMemo, useCallback, useReducer; React 18 added useId, useTransition, useDeferredValue and useSyncExternalStore.
Two rules — always say them:
Call them at the top level only — never inside an if, a loop, or a nested function.
Call them only from a function component or a custom hook.
Why the first rule exists — that is the follow-up. React does not know what your hook is called. It keeps each hook’s state in a linked list, indexed by call order. Put a hook inside an if, skip it on one render, and every index after it shifts — useState hands you somebody else’s value. Say “by call order, not by name” and they know you really understand it.
JSX为什么不能写在条件里示意Illustrative
1// ✗ 顺序会变,后面所有 hook 错位
2functionBad({show}){
3if(show){
4const[a]=useState(1);// 有时调有时不调
5}
6const[b]=useState(2);// b 可能拿到 a 的槽位
7}
8
9// ✓ hook 在顶层,条件放里面
10functionGood({show}){
11const[a]=useState(1);
12const[b]=useState(2);
13useEffect(()=>{
14if(!show)return;// 条件判断放 effect 内部
15// ...
16},[show]);
17}
1// ✗ the order changes, and every hook after it shifts
2functionBad({show}){
3if(show){
4const[a]=useState(1);// called sometimes, skipped other times
5}
6const[b]=useState(2);// b may end up in a's slot
7}
8
9// ✓ hooks at the top level, the condition inside
10functionGood({show}){
11const[a]=useState(1);
12const[b]=useState(2);
13useEffect(()=>{
14if(!show)return;// put the condition inside the effect
In one line:useMemo caches “what a function returns”, useCallback caches “the function itself”. Both use the dependency array to decide whether to recompute.
In fact useCallback(fn, deps) is exactly the same thing as useMemo(() => fn, deps) — the former is sugar for the latter. Saying this scores points.
What it caches
When to use it
useMemo
A computed result (value / object / array)
① the work is genuinely expensive (sorting or filtering a big list) ② the result goes to a memo component as a prop ③ the result is a dependency of another hook
useCallback
A function reference
① the function goes to a memo component ② the function is a dependency of useEffect③ the function is part of a custom hook’s public API
When not to use them — most people miss this half: both cost something — the old value is kept and the dependencies get compared. Wrapping a + b in useMemo is a pure loss. “Measure first, then optimise”: leave them out by default and add them when the profiler says so.
The most common misuse: wrapping something in useCallback but putting a value that changes every render in the dependency array — the cache never hits, and you paid for the comparison on top.
Follow-up: “What changes with the React 19 compiler?” — React Compiler can insert memoisation for you, so most hand-written useMemo and useCallback will stop being necessary. Knowing the direction shows you are keeping up.
In one line:React.memo works at the “component” level — it decides whether to re-render a whole component; useMemo works at the “value” level — it decides whether to recompute one value.
React.memo
useMemo
What it is
A higher-order component
A hook
Where it goes
Wrapped around the component
Inside the component
What it compares
props (shallow)
the dependency array
What it saves
one component render
one computation
The key point: all three go together. Dropping React.memo on a child usually does nothing at all — the parent hands down fresh object and function literals on every render, so the shallow compare is bound to say “changed”. You must also stabilise objects with useMemo and functions with useCallback.
Follow-up: “Can memo stop a context change?” — no it cannot. memo only compares props; context travels a separate channel. That is why a context value has to be wrapped in useMemo — exactly the point of our theme switching variant, where deleting the useMemo left every behaviour test green and only the reference-stability test red. “Does children break memo?” — yes. children is a prop too, and JSX produces a new element object every time.
In one line: pull “logic that carries state” out so it can be reused. The name must start with use.
Why the use prefix is mandatory — this is the point being tested, and it is not about style:
ESLint uses the prefix to recognise it as a hook so it can enforce the rules of hooks (react-hooks/rules-of-hooks). Without the prefix, you can break those rules inside it and nobody warns you.
It is also a signal to whoever reads the code: this function may hold state, so there are limits on where you may call it.
The key idea: you reuse the logic, not the state. Two components that each call useCounter() get two completely independent pieces of state. To share state you need Context or a state library. This is a frequent follow-up and a lot of people get it wrong.
When to extract one: the same combination of useState and useEffect shows up in two or more places; or the effect logic in one component has grown long enough that you can no longer read the component itself.
Follow-up: “What can a custom hook return?” — anything. The convention is “return an array like useState does” (so the caller can rename freely) and “return an object once there are three or more values” (so nobody has to remember the order). “Can it call other hooks?” — yes, that is the whole point; the same two rules still apply.
99 道来自面试题库 #269–#387;TypeScript 深度那 6 道是 DrillLab 自出的(senior 补强,卡片上有标注)。答案都是 DrillLab 写的,所以讲解里的代码块一律标「示意」。每道题都能点回它出处的那一节课。99 questions come from the interview bank (#269–#387); the 6 TypeScript deep-dive ones are DrillLab-made (marked on the card). All answers are written by DrillLab, so every code block here is labelled “demo”. Each card links back to the lesson it came from.