react · high priority
React 성능 — 측정·분할·가상화·양보
"느낌" 이 아니라 *Profiler · INP · 번들 크기* 로 잡는 실전 가이드
학습 개요
탄생 배경
쉬운 설명
복잡한 개념을 실생활 비유로 설명합니다.
“식당의 세 가지 느림”
주문이 들어오자마자 만드는 음식은 *INP* — 셰프(메인 스레드) 가 다른 요리에 묶여 있으면 늦어집니다. 손님이 가게에 들어와 메뉴를 받기까지가 *LCP* — 부엌 입구가 좁거나 메뉴판이 두꺼우면 늦어집니다. 음식이 나오는 동안 의자가 흔들리는 게 *프레임 드롭* — 의자(스크롤) 의 다리가 부실하면 흔들립니다. 셋은 다른 문제라 처방이 다릅니다 — 셰프 일 양보(useTransition), 메뉴판 분권(코드 스플리팅), 의자 다리 보강(가상화).
핵심 개념
| 증상 | 측정값 | 주된 원인 | 처방 1순위 |
|---|---|---|---|
| 클릭/타이핑이 끊긴다 | INP > 200 ms | 한 렌더가 메인 스레드 점유 | Profiler + useTransition/useDeferredValue |
| 첫 화면이 늦게 뜬다 | LCP > 2.5 s, TTFB 큼 | 큰 초기 번들 / 데이터 대기 | 코드 스플리팅 / Streaming SSR |
| 스크롤이 끊긴다 | long animation frame > 16 ms | 대량 DOM / 동기 레이아웃 | 가상화 / content-visibility |
| 새로고침마다 느리다 | Total Blocking Time 큼 | JS 파싱·실행 시간 | 번들 분할 / 의존성 다이어트 |
안티 패턴: "일단 memo 부터"
메모이즈는 *부적절한 리렌더* 를 줄이는 도구지, 큰 번들이나 대량 DOM 을 작게 만들지 못합니다. INP/LCP/프레임 드롭 중 *어느 것이 문제인지* 를 먼저 확인하지 않으면 엉뚱한 처방으로 시간을 씁니다.
실무 적용
어떤 상황에서 사용하는가
관리자 대시보드에서 (a) 첫 로딩이 4 초 (b) 필터 변경 시 입력이 끊김 (c) 1만 행 테이블에서 스크롤이 버벅댐 — 세 종류 불만이 한꺼번에 들어왔다.
어떻게 적용하는가
(a) 번들 분석으로 큰 의존성(차트 라이브러리, moment.js, 어드민 전용 코드) 발견 → 라우트 분할 + 모달/차트 lazy + dayjs 로 교체. (b) Profiler 로 필터 변경 시 광범위 Context 리렌더 발견 → Context 분리 + 무거운 결과 갱신을 `startTransition` + `Suspense` 로 감싸 이전 결과 유지. (c) 1만 행 테이블은 `@tanstack/react-virtual` 로 가상화. 이후 web-vitals 의 INP/LCP 가 회귀 없는지 RUM 으로 7일 모니터링.
흔한 실수와 안티패턴
- 메모이즈를 우선 시도해 시간을 쓰지만 INP 가 안 줄어듦 — 측정 없이 처방했기 때문.
- lazy 를 너무 잘게 적용해 청크가 50+ 로 쏟아지며 오히려 첫 paint 가 늦어짐.
- 가상화 후 항목 안 검색이 깨짐 (Ctrl+F 미스 등) — 사용 시나리오 확인 필요.
- `useTransition` 안에서 `flushSync` 를 섞어 우선순위 의도를 망침.
- Strict Mode 의 이중 렌더를 프로덕션 측정값으로 잘못 해석.
흔한 오해
"`React.memo`/`useMemo` 만 더 붙이면 빨라진다."
교정메모이즈는 *부적절한 리렌더* 처방이지, 큰 번들이나 대량 DOM 을 줄이지 못한다.
왜 중요INP, LCP, 프레임 드롭은 다른 문제다. 측정값으로 어느 영역인지 가르고 처방을 골라야 한다.
"`React.lazy` 는 항상 좋다."
교정네트워크 라운드트립 비용이 분할 이득을 깎을 수 있다.
왜 중요청크가 너무 작으면 다운로드/실행 분산 비용이 커진다. 라우트·큰 모달·잘 안 쓰는 어드민 정도가 1차 후보.
"가상화는 긴 리스트에 무조건 좋다."
교정a11y, 검색, 인쇄, SEO 측면에서 한계가 있다.
왜 중요브라우저 페이지 검색이 안 보이는 항목을 못 찾고, 스크린리더 경험도 라이브러리에 따라 다르다. 짧은 리스트엔 `content-visibility: auto` 가 더 적합할 때가 많다.
면접 질문
답변 방향 힌트
"증상 → 측정값 → 원인 → 처방 → 재측정" 으로.
반드시 언급할 키워드
- 먼저 *어떤* 느림인지 확인 — INP/LCP/프레임 드롭
- Profiler + Performance + web-vitals(RUM) 으로 측정
- 원인별 처방 — 메모이즈 / 스플리팅 / 가상화 / 양보
- 재측정으로 회귀 확인
- 비즈니스 KPI(이탈률·전환율) 로 임팩트 검증
예상 꼬리 질문
- Lab 측정과 RUM 의 차이가 클 때 어디부터 의심하나요?
- 비즈니스 KPI 와 성능을 연결하는 방법은?
자기 점검
INP 가 LCP 보다 면접에서 자주 다뤄지는 이유 한 가지를 답하라.
기대 키워드
자주 하는 오해
"INP 가 더 새 지표라 그렇다" 는 절반의 답. 본질은 React 코드와 직접 묶여 있어 *지원자의 코드 실력* 을 평가하기 좋다는 점.
메모이즈로는 거의 효과를 못 보는 대표 시나리오 한 가지를 한 문장으로.
기대 키워드
자주 하는 오해
"useMemo 를 더 적극적으로" 가 답이 아니다 — 결과가 매번 다른 패턴에선 캐시 히트가 거의 없다.
가상화 도입 후 *잃을 수 있는* 비기능 한 가지를 답하라.
기대 키워드
자주 하는 오해
"가상화는 무조건 좋다" 는 답에서 멈추면 시니어 답으로 부족하다.
학습 자료
- React Profiler — DevTools시나리오 녹화·Ranked·Flamegraph 사용법, 측정 모드와 dev/prod 차이.Docreact.dev
- web-vitalsINP/LCP/CLS 정의·측정 방법·임계치, RUM 수집 라이브러리.Docweb.dev
- `React.lazy` — Referencelazy 의 의미론과 Suspense 와의 결합, 흔한 함정.Docreact.dev
- `@tanstack/react-virtual`가변 높이·sticky 등 실전에 필요한 기능을 갖춘 가상화 라이브러리.CodeTanStack
- Optimizing Interaction to Next Paint (INP)INP 측정 원리·개선 패턴 — `requestIdleCallback`·yield·우선순위 양보 패턴 정리.Blogweb.dev