Conclusion
- Hooks cannot be written in conditions, it is not a grammatical restriction,
- But because React uses "call order" to align Hook state to Fiber.
Once the order is unstable, The state will be dislocated and cannot be restored.
2. How does Hooks “position itself”?
We already know:
txt
Fiber.memoizedState
└─ hook1 → hook2 → hook3 → nullEach render:
txt
currentHook → 指向旧链表
workInProgressHook → 构建新链表There is only one positioning rule:
The Nth call to useX() corresponds to the Nth hook node
no key no name No AST only order
3. Conditional statements directly destroy this unique rule.
1️⃣ Normal situation (stable order)
ts
useState() // hook #1
useEffect() // hook #2
useMemo() // hook #3Each render is:
txt
##1 → #2 → #3✔ Correct
2️⃣ Conditional Hook (the order is unstable)
ts
useState() // hook #1
if (cond) {
useEffect() // ❌ 有时执行,有时不执行
}
useMemo() // hook ? ❌render #1(cond = true)
txt
##1 useState
##2 useEffect
##3 useMemorender #2(cond = false)
txt
##1 useState
##2 useMemo ❌ 本来是 #34. Source code level dislocation process (the part you care about)
updateWorkInProgressHook simplified version:
ts
function updateWorkInProgressHook() {
const nextCurrentHook = currentHook.next
const newHook = clone(nextCurrentHook)
currentHook = nextCurrentHook
workInProgressHook.next = newHook
workInProgressHook = newHook
}React By default you will call the next Hook every time.
When you skip a Hook:
currentHookis not moving forwardworkInProgressHookbut keeps moving forward- The linked list is directly misaligned
5. What will be caused by misalignment?(real disaster)
Misalignment is not as simple as "executing one less effect"
Example:
ts
const [a, setA] = useState(1)
if (cond) {
useState(2)
}
const [b, setB] = useState(3)Result:
bmight get2setBoperates on the wrong queue- update lane wrongly tied fiber
- ❌ Behavior is unpredictable
👉 This is no longer a bug, it’s state pollution
6. Why doesn’t React use “name/key” to mark Hook?
You will definitely think of this issue at this level.
Theoretically possible, but the cost is extremely high:
1️⃣ Each render requires:
- Parse AST
- Create key mapping
- diffHook structure
2️⃣ render is no longer:
txt
Component(props) → JSXAnd becomes:
txt
Component → 解析 → 调度👉 This directly negates Fiber’s “rerunable render” design
7. Why doesn’t Vue have this problem?
Vue effect:
ts
watchEffect(() => {
if (cond) {
console.log(a.value)
}
})✔ No problem because:
- Effect is dynamic dependency collection
- not in order
- Regardless of location
- Not relying on render
👉 The inevitable result of the two models
8. StrictMode dual execution, why hasn’t it exploded yet?
Because:
- mount → unmount → mount
- Complete sequence every time
- Not “one less Hook”
9. The real rule (not “can’t write if”)
- ❌ Misunderstanding: Hooks cannot be written in if
- ✅ Correct understanding: The calling sequence of Hooks must be completely consistent in each render
So these are allowed:
ts
useEffect(() => {
if (cond) {
// 可以
}
}, [cond])ts
const value = cond ? useMemo(...) : other
// ❌ 不允许(顺序不稳定)10. The ultimate one-sentence summary (for you this kind of principle school)
Hooks rules are not restrictive to developers,
Instead, Hooks uses "sequence" in exchange for:
- No identification required
- No need to compile
- Interruptible render
- Extremely low runtime cost
This is a very "React-y" deal.