응답 순서가 아니라 request ID가 state 쓰기를 결정한다

dependency가 바뀌면 이전 요청을 정리하고, 늦게 도착한 응답은 최신성 gate를 통과할 때만 commit한다.

요청 A가 늦게 와도 최신 UI를 덮지 못한다

시간 →
t1
query=a
t2
query=ab
t3
B 응답
t4
A 응답
최종 state
Request A
A 시작 · id=1
cleanup · abort
id 1 ≠ current 2
차단
Request B
B 시작 · id=2
id 2 = current 2
commit
data = B
t1 · A 시작id=1 · query=a
t2 · A 정리, B 시작A abort · id=2 · query=ab
t3 · B 응답id 2 = current 2 → commit
t4 · A 늦은 응답id 1 ≠ current 2 → 차단 · data=B 유지
1
dependency snapshot

요청 ID와 기준값을 묶어 이번 요청의 정체를 고정한다.

2
cleanup / abort

다음 effect 전에 이전 controller를 취소해 영향 범위를 끊는다.

3
commit gate

최신 요청만 loading·data·error 상태를 바꾼다. AbortError는 사용자 오류로 표시하지 않는다.

mount once

처음 한 번만 필요한 데이터

빈 배열은 초기 로드에는 맞지만 입력 변화에는 반응하지 않는다.

[]
by id

조건이 바뀌는 데이터

userId·query·filter처럼 결과를 바꾸는 값은 dependency에 둔다.

[userId]
unsafe

매번 새 객체

매 렌더 새 options를 넣으면 요청 폭주와 stale response가 생긴다.

[options]

핵심cleanup은 이전 요청을 끝내고, gate는 이미 도착 중인 오래된 응답의 state 쓰기를 막는다. 둘을 함께 둬야 경쟁 상태가 닫힌다.