FEInterview Prep

외부 원문 링크

리액트 19.2.0의 새로운 기능

React 19.2 의 주인공은 <Activity>, useEffectEvent, cacheSignal, *부분 프리렌더링*. 컴포넌트 *생명주기/이펙트/SSR* 세 축에서 거친 모서리를 다듬은 마이너 릴리스다.

2025-10-29·7분 읽기
React성능
원문 보기 ↗

핵심 요약

주요 변경 사항을 도구별로:

// 1) <Activity> — 보이지 않을 때 상태 유지 + 작업 우선순위 다운
<Activity mode={isVisible ? 'visible' : 'hidden'}>
  <Page />
</Activity>

// 2) useEffectEvent — 이펙트 의존성에 안 넣고 최신 값 사용
const onConnected = useEffectEvent(() => {
  showNotification('Connected!', theme); // 항상 최신 theme
});
useEffect(() => {
  const c = createConnection(serverUrl, roomId);
  c.on('connected', () => onConnected());
  c.connect();
  return () => c.disconnect();
}, [roomId]); // ✅ onConnected 추가 X

// 3) cacheSignal — 서버 컴포넌트의 비동기 작업 취소 신호
const dedupedFetch = cache(fetch);
async function Component() {
  await dedupedFetch(url, { signal: cacheSignal() });
}

// 4) 부분 프리렌더링 — 정적 → CDN, 동적 → resume
const { prelude, postponed } = await prerender(<App />, { signal });
// ... CDN 으로 prelude, 나중에
const resumeStream = await resume(<App />, postponed);

그 외: SSR Suspense 일괄 처리, Node.js SSR 의 웹 스트림 지원, eslint-plugin-react-hooks@6.1.0 (Flat config 기본), useId prefix 변경(«r»«r»r).

19.2 의 변화는 "새 기능 추가" 가 아니라 "기존 모델의 미해결 통증을 정리" 다. (1) <Activity> — 조건부 렌더의 상태 보존 통증, (2) useEffectEvent — 이펙트 의존성의 최신 값 캡처 통증, (3) 부분 프리렌더링 — SSR 의 정적/동적 분리 통증. 즉 'React 의 모서리를 갈았다' 가 멘탈 모델이다.

면접에서 React 19 가 화제가 되면 보통 Server Components/Actions/use 로 흐른다. 19.2 는 그보다 자주 쓸 작은 도구들 을 추가하기 때문에 다음을 분리해 답할 수 있어야 한다.

  • Activity: 화면 전환 시 언마운트 vs 상태 유지 의 표준 해법
  • useEffectEvent: "의존성에 안 넣고 싶지만 최신 값은 필요" 의 정식 해법 — useRef 패턴을 대체
  • cacheSignal: 서버 컴포넌트의 비동기 정리(cleanup) 가 표준화
  • 부분 프리렌더링: 정적 셀 → CDN 즉시, 동적 부분 → 재개 의 2단 패턴

이걸 언제 쓰는가 까지 답할 수 있으면 시니어 신호다.

학습 포인트

면접 답변으로 연결할 학습 포인트입니다.

`<Activity>` — 조건부 렌더의 표준 진화

기존 패턴 {isVisible && <Page />}언마운트 라 상태(스크롤/입력값)가 사라진다. 보존하려면 CSS display:none + 수동 aria-hidden 같은 헛스러운 패턴을 쓰던 게 현실이었다.

<Activity mode={isVisible ? 'visible' : 'hidden'}>
  <Page />
</Activity>

동작:

  • hidden — 자식 숨김, 이펙트 언마운트, 업데이트는 다른 작업이 끝날 때까지 연기
  • visible — 자식 표시, 이펙트 마운트, 정상 우선순위

쓸 곳: 탭/모달/사이드 패널 의 백그라운드, 다음 라우트 프리로드, 폼 입력값 보존. 즉 언마운트와 상태 보존 사이의 빈 자리를 표준화한 것.

Activityconcurrent renderinghiddenpreload
자주 하는 오해

"display:none 으로 충분하지 않냐" 라고 보는 것. CSS 는 우선순위 다운/업데이트 연기 같은 React 스케줄러 통합이 안 된다 — 큰 차이다.

`useEffectEvent` — 의존성 지옥의 정식 출구

useEffect 안에서 최신 props/state 를 쓰면서 그것 때문에 다시 실행되지 않게 하는 것은 그동안 useRef 패턴으로 우회해왔다. 19.2 는 이를 이벤트 함수 로 정식화한다.

const onConnected = useEffectEvent(() => {
  showNotification('Connected!', theme); // 최신 theme
});

useEffect(() => {
  const c = createConnection(serverUrl, roomId);
  c.on('connected', () => onConnected());
  c.connect();
  return () => c.disconnect();
}, [roomId]); // theme 변경에도 재연결 X

핵심 의미: "이펙트는 동기화 목적, 이벤트는 즉시 액션" 의 경계가 코드로 표현 된다. lint(react-hooks@6.1.0) 가 잘못된 사용을 잡아준다.

useEffectEventsynchronizationevent vs effectstale closure
자주 하는 오해

useEffectEvent모든 콜백에 쓰는 것. 이벤트 함수는 이펙트 안에서만 호출 해야 한다 — 외부에서 호출하면 의도가 깨진다.

부분 프리렌더링 — *정적/동적* 의 2단 배포

프리렌더링은 "정적 셸 즉시 + 동적 채움 재개" 의 표준 API 가 됐다.

// 1) 빌드/배포 — 정적 셸
const { prelude, postponed } = await prerender(<App />, {
  signal: controller.signal,
});
await savePostponedState(postponed);
// prelude 는 CDN 으로

// 2) 요청 시 — 재개
const postponed = await getPostponedState(req);
const stream = await resume(<App />, postponed); // SSR
// 또는 SSG 완전 정적
const { prelude } = await resumeAndPrerender(<App />, postponed);

장점:

  • TTFB 빨라짐 (정적 셸 CDN 즉답)
  • 로직 분리 (정적/동적 경로가 명확)
  • Suspense 일괄 처리 와 결합해 스트리밍 깜빡임 감소

단점: 인프라가 postponed 상태 저장소 를 가져야 한다 — 운영 복잡도 상승.

prerenderresumepostponedstreaming SSR
자주 하는 오해

ISR/SSR/SSG 와 같은 것 으로 보는 것. 부분 프리렌더링은 한 페이지 안에서 정적/동적이 공존 — 차원이 다르다.

읽는 순서

  1. 1이론

    React 19.2 릴리스 노트와 useEffectEvent / Activity / 부분 프리렌더링 RFC 를 한 시간 안에 훑고, 각 기능의 기존 우회 패턴 을 옆에 적어 비교 표로 만드세요.

  2. 2구현

    탭 UI 하나를 골라 <Activity> 로 마이그레이션. 스크롤/입력값 보존을 React DevTools 로 검증하세요. 그리고 useRef 우회 한 곳을 useEffectEvent 로 옮기고 lint 경고 사라짐을 확인.

  3. 3실무

    프로젝트에 eslint-plugin-react-hooks@6.1.0 으로 업그레이드. Flat config 기본을 켜고 recommended-legacy 가 필요한 코드부터 점진 이행.

  4. 4설명

    팀에 10분 발표 — '19.2 의 4가지 작은 도구가 우리 코드의 어떤 우회 패턴을 정리하는가'. 각 도구마다 전/후 코드 비교 슬라이드 한 장씩.

면접 연결 질문

medium`<Activity>` 가 `display:none` 이나 `{isVisible && ...}` 보다 나은 점을 두 가지 이상 답해보세요.
힌트

[감점 답변] '편하다'. [좋은 답변] (1) 상태 보존: 언마운트되지 않으므로 스크롤/입력값 유지. (2) 스케줄러 통합: hidden 시 업데이트가 다른 작업 끝까지 연기 되어 백그라운드 비용을 자동으로 낮춤. (3) 이펙트 라이프사이클: 보일 때만 마운트되어 리소스/구독 관리 정확도 향상. CSS 는 1번/3번을 동시에 해결할 수 없다.

medium`useEffectEvent` 의 사용 규칙 두 가지를 답해보세요.
힌트

[감점 답변] '그냥 쓰면 됨'. [좋은 답변] (1) 이펙트 안에서만 호출 — 컴포넌트 본문/이벤트 핸들러에서 직접 호출하면 안 됨. (2) 의존성에 넣지 말 것 — 넣으면 의도가 깨진다. lint 규칙이 위반을 잡아주므로 eslint-plugin-react-hooks@6.1.0 으로 업그레이드 필수.

hard부분 프리렌더링이 *기존 SSR* 대비 어떤 운영 트레이드오프를 만드는지 답해보세요.
힌트

[감점 답변] '더 빠름'. [좋은 답변] 두 측면. (1) 이득: 정적 셸이 CDN 캐시되어 TTFB 매우 짧음, 동적 부분만 origin 부담. (2) 비용: postponed 상태를 저장/조회 할 인프라가 필요하고, 빌드/런타임 양쪽 코드를 같은 트리에서 관리. 작은 프로젝트엔 과한 도입, 큰 트래픽엔 origin CPU 절감 으로 ROI 양호.

자기 점검

본인 프로젝트에서 `<Activity>` 를 적용하면 가장 효과 클 화면 한 곳을 고르고 *어떤 상태가 보존되어야 하는지* 적어보세요.
스크롤 위치폼 입력preload
자주 하는 오해

"모든 화면에 적용" 이라는 과도한 일반화. 전환이 잦고 상태 보존 가치가 큰 곳 에 한정해야 의미가 있다.

`useEffect` 의 의존성 배열 lint 경고를 *useRef 우회* 로 해결하던 코드를 `useEffectEvent` 로 바꾸면 무엇이 좋아지는지 한 단락으로 답해보세요.
stale closure최신 값재실행lint
자주 하는 오해

useRef 패턴이 동등하다 는 인식. 실제로는 lint 가 의도 위반을 못 잡고, 코드 의도가 동기화/이벤트 로 분리되지 않는다.

`useId` prefix 변경(`«r»` → `r`) 이 어떤 *실제 문제* 때문에 필요했는지 설명해보세요.
view-transition-nameXML 1.0CSS 식별자유효성
자주 하는 오해

"디자인 결정" 이라는 인식. 실제로는 View Transitions / view-transition-name 같은 표준이 XML 1.0 호환 식별자 를 요구해 발생한 호환성 강제 다.