고래를 찾는데 고양이가 나타났다 · 과거의 응답이 오늘을 바꾸지 못하게 · 실습
늦게 온 응답을 돌려보내는 검색 hook
목표
React+TypeScript 검색 hook을 직접 구현하고, 오래된 응답과 취소·재시도·예외를 검사합니다.
제공 UI에서 실제 React 화면을 보며 연습합니다. HTML 폼 작성과 긴 목록 최적화 전체를 이 한 실습으로 대신하지 않습니다.
왜 중요한가
성공한 응답도 현재 사용자의 의도와 다르면 잘못된 화면입니다. 취소는 자원 회수이고 결과 무시는 화면의 정확성입니다.
두 책임을 분리하면 취소를 지원하지 않는 비동기 도구도 시험할 수 있습니다. Promise의 거절과 호출 시 throw 역시 다른 경로입니다.
함수·클로저·Promise·TypeScript 유니온과 기본 React hook을 읽을 수 있어야 합니다.
준비
처음 한 번 node /opt/react-workbench/prepare.mjs /root/react-search-lab lesson을 실행하세요.
이미 존재하면 기존 사본을 계속 사용하세요. 지우거나 덮어쓰지 않습니다. 런타임 npm install은 필요 없습니다.
수정 파일은 /root/react-search-lab/src/useSearch.ts입니다. 함께 제공된 src/types.ts에서
Query(text, revision), Search(query, signal), SearchState의 다섯 상태 계약을 읽으세요.src/types.ts와 제공 search의 동작은 바꾸지 않습니다. 단계 예시는 최초 틀이며 정답이 아닙니다.
단계
1. 검색을 보내기 전과 기다릴 때를 나눈다 — lesson 모드로 /root/react-search-lab 사본을 준비하세요. src/useSearch.ts에 useSearch(request, search)를 export하고 SearchState를 반환합니다. 빈 request.text는 idle, 비어 있지 않으면 loading과 해당 query입니다. 입력을 비워 새로 제출하면 idle로 돌아옵니다. 응답 처리는 다음 단계입니다.
2. 성공·빈 결과·실패에 다른 안내를 준다 — 주어진 search(request.text, controller.signal)를 호출하세요. 1개 이상 결과는 success와 원래 items, 0개는 empty, Error 거절은 error와 error.message입니다. 각 상태에 해당 query를 유지하고, 실패 후 새 검색은 loading을 거쳐 성공할 수 있어야 합니다. search를 자체 구현으로 교체하지 마세요.
3. 고양이가 고래 화면을 빼앗지 못하게 한다 — 여러 검색을 제출하고 응답을 역순으로 완료해도 최신 제출의 결과만 남게 하세요. 최신 요청이 실패한 뒤 오래된 성공이 도착해도 최신 오류를 유지합니다. 취소를 무시하는 전송에서도 성립해야 합니다.
4. 오래된 장애 안내도 버린다 — 최신 성공 뒤 오래된 실패, 최신 실패 뒤 더 오래된 실패가 와도 화면을 바꾸지 못하게 하세요. 최신 요청의 Error.message는 그대로 보존합니다. 앞 단계 성공 응답 보호도 유지합니다.
5. 필요 없는 요청을 정리한다 — 새 제출로 effect가 바뀔 때 이전 요청의 signal.aborted가 true가 되게 하세요. 최신 요청은 필요할 동안 false여야 하고, 컴포넌트 해제 시 true여야 합니다. 취소 여부와 늦은 응답 무시를 각각 유지합니다.
6. 같은 단어의 새 의도를 구별한다 — Query의 revision이 달라진 동일 검색도 새로운 요청이어야 합니다. 같은 단어의 두 요청을 역순으로 완료하면 새 결과만 남습니다. 빈 제출은 idle로 돌아가고 이전 응답이 결과를 복원하지 못해야 합니다.
7. Promise를 받기도 전에 난 오류를 처리한다 — search가 Promise를 반환하기 전에 Error를 던져도 React 화면 전체가 죽지 않고 error와 그 message를 표시하게 하세요. 이후 새 검색으로 정상 복구할 수 있어야 합니다. 비동기 거절·취소·경합 계약도 유지합니다.
8. 설정·정리를 반복하고 전체 계약을 재검사한다 — 개발 StrictMode의 설정→정리→재설정에서 첫 요청은 취소되고, 첫 응답이 늦게 와도 두 번째 결과가 남는지 검사하세요. 전체 채점으로 1~7단계와 이 조건을 함께 확인합니다. npm run typecheck와 npm run build 후 3000 포트 미리보기에서 역순 성공·실패·빈 결과·재시도를 직접 확인하세요.
참고
작업 폴더에서 npm run typecheck, npm run build, npm start 순으로 실행하면http://127.0.0.1:3000/ 미리보기를 볼 수 있습니다. 마지막 /를 유지하세요.
소스를 바꾸면 다시 빌드하고 미리보기를 새로 고칩니다. 시작 단계에서는 아직 응답이 표시되지 않을 수 있습니다.
수동 배달은 HTTP가 아닌 결정적 Promise 모형입니다. 실제 HTTP 비교 화면에서는 실습 서버의 합성 자료를 받습니다.
채점은 학생 hook의 strict 타입과 실제 React+jsdom 상태를 검사하며 학생 파일을 변경하지 않습니다.
이 검사는 실제 브라우저 레이아웃·성능·스크린리더 사용성 검증을 대신하지 않습니다.
각 단계는 앞 단계도 누적 검사합니다. 128KiB 이하 일반 소스 파일, 작업 프로세스 12초 제한을 적용합니다.
마지막 회귀 단계는 이전 정답으로 통과할 수 있습니다. 새 기능 대신 기존 계약을 재검증하기 때문입니다.
필요하면 +시간으로 세션을 연장하고 종료 전에 수정 소스와 관찰 기록을 따로 저장하세요. 세션 종료 후 파일은 유지되지 않습니다.
단계 8개
- 검색을 보내기 전과 기다릴 때를 나눈다
- 성공·빈 결과·실패에 다른 안내를 준다
- 고양이가 고래 화면을 빼앗지 못하게 한다
- 오래된 장애 안내도 버린다
- 필요 없는 요청을 정리한다
- 같은 단어의 새 의도를 구별한다
- Promise를 받기도 전에 난 오류를 처리한다
- 설정·정리를 반복하고 전체 계약을 재검사한다