10월 1일 React 19.2 가 출시되었습니다 🎉
무엇이 추가되었는지 한번 알아보아요~!! 🤗
<Activity /><Activity> 를 사용하면 앱을 제어하고 우선순위를 나눌 수 있는 "활동"으로 나눌 수 있습니다.
Activity 를 조건부로 앱을 렌더링하는 대안으로 사용할 수도 있습니다.
// Before
{isVisible && <Page />}
// After
<Activity mode={isVisible ? 'visible' : 'hidden'}>
<Page />
</Activity>
React 19.2 에서는 Activity 는 2가지의 모드를 제공합니다: visible & hidden.
hidden: 자식 요소를 숨깁니다, effect 를 언마운트합니다, React 에서 작업할 것이 없을 때까지 모든 업데이트를 연기합니다.visible: 자식 요소를 보여줍니다, effect 를 마운트합니다, 업데이트가 정상적으로 처리되도록 합니다.이는 당신이 스크린에 무언가 보이거나, 성능에 영향을 미치지 않으면서 앱의 숨겨진 부분을 미리 렌더링하거나 계속 렌더링할 수 있다는 것을 의미합니다.
유저가 다음에 이동할 가능성이 높은 숨겨진 부분을 Activity 를 사용해 렌더링하거나, 유저가 이동한 부분의 상태를 저장할 수 있습니다. 이는 데이터, css, 이미지들을 백그라운드에서 로딩해서 유저가 빠르게 이동할 수 있도록 도울 수 있으며, 뒤로 이동 시 input field 와 같은 부분의 상태를 유지하도록 할 수 있습니다.
이후에 다양한 사용 사례들을 위한 모드들을 Activity 에 더할 계획입니다.
useEffectEventuseEffect 의 흔한 패턴은 외부 시스템에서 발생하는 이벤트를 앱 코드에 알리는 것입니다. 예를 들어 채팅방에 접속하면 다음과 같은 알림을 받을 수 있습니다.
function ChatRoom({ roomId, theme }) {
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.on('connected', () => {
showNotification('Connected!', theme);
});
connection.connect();
return () => {
connection.disconnect()
};
}, [roomId, theme]);
// ...
위 코드의 문제점은 이러한 "이벤트" 내부에서 사용되는 값을 변경하면 주변 Effect 가 다시 실행된다는 것입니다. 예를 들어, theme 을 변경하면 채팅창이 다시 연결됩니다. 이는 roomId 와 같이 Effect 로직 자체와 관련된 값에는 적합하지만, theme 에는 적합하지 않습니다.
이 문제를 해결하기 위해 대부분의 사용자들은 린트 규칙을 끄고 종속성을 제외합니다. 하지만 이렇게 하면 나중에 Effect 를 업데이트해야 할 때 린터가 종속성을 최신 상태로 유지하는 데 도움이 되지 않아 버그가 발생할 수 있습니다.
useEffectEvent 를 사용한다면, 로직의 "이벤트" 부분을 이를 방출하는 Effect 에서 제외할 수 있습니다.
function ChatRoom({ roomId, theme }) {
const onConnected = useEffectEvent(() => {
showNotification('Connected!', theme);
});
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.on('connected', () => {
onConnected();
});
connection.connect();
return () => connection.disconnect();
}, [roomId]); // ✅ All dependencies declared (Effect Events aren't dependencies)
// ...
DOM 이벤트와 비슷하게, Effect 이벤트는 항상 최신 prop 과 상태를 보고 있습니다.
Effect 이벤트는 의존성 배열에 선언하면 안됩니다. 린터가 이를 의존성에 추가하지 않도록 eslint-plugin-react-hooks@6.1.0 으로 업그레이드해야 합니다. Effect 이벤트는 동일한 컴포넌트 또는 Hook 에서만 "해당" Effect로 선언될 수 있습니다. 이러한 제한 사항은 린터를 통해 검증됩니다.
useEffectEvent를 사용해야 할 때
개념적으로 사용자 이벤트가 아닌 Effect 에서 발생하는 "이벤트"인 함수에는useEffectEvent를 사용해야 합니다. (이것이 바로 "Effect 이벤트"의 정의입니다.) 모든 것을useEffectEvent로 감싸거나, 단순히 린트 오류를 없애기 위해 사용할 필요는 없습니다. 버그가 발생할 수 있습니다.
Effect Event 에 대해 자세히 알아보려면 이벤트에서 효과 분리 를 참고하세요.
cacheSignal
cacheSignal은 React 서버 컴포넌트에서만 사용할 수 있습니다.
cacheSignal 은 cache() 의 수명이 언제 끝났는지 알 수 있습니다.
import {cache, cacheSignal} from 'react';
const dedupedFetch = cache(fetch);
async function Component() {
await dedupedFetch(url, { signal: cacheSignal() });
}
이를 사용해 작업이 더이상 캐시에서 사용되지 않을 때 중단하거나 정리할 수 있습니다.
추가적인 정보는 cacheSignal 문서 를 참고하세요.
React 19.2 는 크롬 개발자 도구 성능 프로필에 새로운 커스텀 추적 을 더해 React 앱의 성능에 대한 자세한 정보를 제공합니다.

React 성능 추적 문서 가 추적에 포함된 모든 것을 설명해주지만, 여기에선 간략한 요약을 소개합니다.
스케줄러 추적은 사용자 상호작용을 위한 "차단"이나 startTransition 내에서 업데이트를 위한 "전환"과 같은 다양한 우선순위에 대해 React 가 어떤 작업을 수행하는지 보여줍니다. 각 추적 내에서 업데이트를 예약한 이벤트와 해당 업데이트의 렌더링 시간 등 수행 중인 작업 유형을 확인할 수 있습니다.
또한 업데이트가 다른 우선순위를 기다리느라 차단되거나 React 가 페인트 작업을 기다린 후 작업을 계속 진행하는 경우와 같은 정보도 표시합니다. 스케줄러 트랙은 React 가 코드를 여러 우선순위로 어떻게 분할하고 작업을 완료했는지 이해하는 데 도움이 됩니다.
포함된 내용은 스케줄러 추적 문서 를 참고하세요.
컴포넌트 추적은 React 가 렌더링하거나 효과를 실행하기 위해 작업 중인 컴포넌트 트리를 보여줍니다. 내부에는 자식 컴포넌트가 마운트되거나 효과가 마운트될 때 "마운트", React 외부 작업에 양보하여 렌더링이 차단될 때 "차단됨"과 같은 라벨이 표시됩니다.
컴포넌트 추적은 컴포넌트가 렌더링되거나 효과를 실행할 때와 해당 작업을 완료하는 데 걸리는 시간을 파악하여 성능 문제를 파악하는 데 도움이 됩니다.
포함된 내용은 컴포넌트 추적 문서 를 참조하세요.
19.2 에서는 앱의 일부를 미리 렌더링하고 나중에 렌더링을 재개하는 새로운 기능을 추가합니다.
이 기능은 "부분 사전 렌더링"이라고 하며, 앱의 정적 부분을 미리 렌더링하여 CDN에서 제공한 다음, 셸 렌더링을 재개하여 나중에 동적 콘텐츠로 채울 수 있습니다.
앱을 나중에 다시 렌더링하려면 먼저 AbortController 와 함께 prerender 를 호출합니다.
const {prelude, postponed} = await prerender(<App />, {
signal: controller.signal,
});
// Save the postponed state for later
await savePostponedState(postponed);
// Send prelude to client or CDN.
그런 다음, prelude 셸을 클라이언트로 반환하고 나중에 resume 을 호출하여 SSR 스트림을 재개할 수 있습니다.
const postponed = await getPostponedState(request);
const resumeStream = await resume(<App />, postponed);
// Send stream to client.
또는 resumeAndPrerender 를 호출하여 SSG(Static-site-Generation) 에 대한 정적 HTML 을 얻을 수 있습니다.
추가적인 정보를 얻고 싶다면 새로운 API 에 대한 아래의 문서를 참고하세요.
react-dom/serverresume: 웹 스트림resumeToPipeableStream: Node.js 스트림react-dom/staticresumeAndPrerender: 웹 스트림resumeAndPrerenderToNodeStream: Node.js 스트림또한, 사전 렌더링 API 는 이제 resume API 에 전달하기 위해 postpone 상태를 반환합니다.
Suspense 경계가 클라이언트에서 렌더링되었는지, 아니면 서버 측 렌더링에서 스트리밍되었는지에 따라 다르게 표시되는 동작 버그를 수정했습니다.
19.2 버전부터 React 는 서버에서 렌더링된 Suspense 경계를 잠시 배치 처리하여 더 많은 콘텐츠를 동시에 표시하고 클라이언트 렌더링 동작에 맞춰 조정할 수 있도록 합니다.

이전에는 스트리밍 서버 측 렌더링 중에 suspense 콘텐츠가 fallback 을 즉시 대체했습니다.

React 19.2 에서는 짧은 시간 동안만 suspense 경계가 배치 처리되어 더 많은 콘텐츠를 동시에 공개할 수 있습니다.
이 수정 사항은 SSR 동안 Suspense에 대한 <ViewTransition> 을 지원하도록 앱을 준비합니다. 더 많은 콘텐츠를 동시에 표시함으로써 애니메이션을 더 큰 규모의 콘텐츠로 실행할 수 있고, 가까이 스트리밍되는 콘텐츠의 애니메이션을 연쇄적으로 실행하는 것을 방지할 수 있습니다.
React 는 휴리스틱을 사용하여 속도 조절이 핵심 웹 바이탈과 검색 순위에 영향을 미치지 않도록 합니다.
예를 들어, 총 페이지 로드 시간이 2.5초 (LCP 에서 "양호"하다고 간주되는 시간) 에 가까워지면 React 는 배치 처리를 중단하고 콘텐츠를 즉시 표시하여 속도 조절이 지표 누락의 원인이 되지 않도록 합니다.
React 19.2 는 Node.js 에서 SSR 스트리밍을 위한 웹 스트림 지원을 추가했습니다.
renderToReadableStream 을 이제 Node.js 에서 사용할 수 있습니다.prerender 을 이제 Node.js 에서 사용할 수 있습니다.새로운 resume API 도 추가되었습니다.
resume 을 이제 Node.js 에서 사용할 수 있습니다.resumeAndPrerender 을 이제 Node.js 에서 사용할 수 있습니다.Node.js 에서는 SSR 을 위해 Node.js 스트림을 되도록 사용하세요
Node.js 런타임에서는 Node.js 의 Stream API 를 사용하는 것을 아직 강하게 추천합니다.이는 Node.js 의 스트림이 Node.js 에서 웹 스트림보다 훨씬 빠르고, 웹 스트림은 기본적으로 압축을 지원하지 않기 때문에 사용자가 실수로 스트리밍의 이점을 놓치는 경우가 발생하기 때문입니다.
eslint-plugin-react-hooks v6또한 권장 사전 설정에서 기본적으로 flat config 를 갖춘 eslint-plugin-react-hooks@6.1.0 을 패치했으며, 새로운 React 컴파일러 기반 규칙을 선택했습니다.
레거시 config 를 계속 사용하려면 recommended-legacy 로 변경하세요.
- extends: ['plugin:react-hooks/recommended']
+ extends: ['plugin:react-hooks/recommended-legacy']
컴파일러가 활성화한 규칙을 모두 보려면 린터 문서 를 확인하세요.
전체 변경 사항은 eslint-plugin-react-hooks change log 에서 확인하세요.
useId 의 기본 prefix 업데이트19.2 에서는 기본 useId prefix 를 :r: (19.0.0) 또는 «r» (19.1.0)에서 _r_ 로 변경합니다.
CSS 선택자에 유효하지 않은 특수 문자를 사용한 원래 의도는 사용자가 입력한 ID 와 충돌할 가능성이 낮도록 하기 위한 것이었습니다. 그러나 뷰 전환을 지원하려면 useId로 생성된 ID가 view-transition-name 및 XML 1.0 이름에 유효한지 확인해야 합니다.
오 편리하게 사용할 수 있는 업데이트들이 많네요. 좋은 글 감사합니다!