번역: https://react.dev/blog/2024/12/05/react-19
React v19 – React
The library for web and native user interfaces
react.dev
React 19가 이제 npm에서 stable 버전으로 출시되었습니다!
이전에 4월에 공유된 React 19 릴리즈 후보(RC) 이후 다음과 같은 기능이 추가되었습니다.
- Suspense 트리 사전 로드(Pre-warming): Suspence 개선 사항을 통해 비동기 데이터 로딩 시 사용자 경험이 향상되었습니다.
- React DOM 정적 API: 새로운 정적 API를 도입하여 서버 사이드 렌더링과 정적 사이트 생성이 더욱 효율적으로 개선되었습니다.
이 게시물의 날짜는 stable 버전 출시일에 맞춰 업데이트되었습니다.
이 게시물에서는 React 19의 새로운 기능과 이를 어떻게 도입할 수 있는지에 대한 개요를 제공합니다.
React 19의 새로운 기능
Actions
React 앱에서 자주 발생하는 사용 사례 중 하나는 데이터 변경 작업(Data Mutation)을 수행한 뒤 상태를 업데이트 하는 것입니다.
예를 들어, 상용자가 이름 변경 form을 제출하면 API 요청을 보내고, 그 응답에 따라 상태를 처리해야 합니다.
기존에는 다음 작업을 수동으로 처리해야 했습니다.
- 대기 상태(pending state): 요청 중인 상태를 관리
- 에러 처리(error handling): 요청 실패 시 에러 메시지 표시
- 낙관적 업데이트(optimistic updates): 요청 중 예상 결과를 미리 반영
- 순차 요청 관리(sequential requests): 열 요청 간의 흐름 제어
기존 방식: useState를 활용한 상태 관리
function UpdateName({}) {
const [name, setName] = useState("");
const [error, setError] = useState(null);
const [isPending, setIsPending] = useState(false);
const handleSubmit = async () => {
setIsPending(true); // 대기 상태 시작
const error = await updateName(name); // API 호출
setIsPending(false); // 대기 상태 종료
if (error) {
setError(error); // 에러 처리
return;
}
redirect("/path"); // 성공시 리다이렉션
};
return (
<div>
<input value={name} onChange={(event) => setName(event.target.value)} />
<button onClick={handleSubmit} disabled={isPending}>Update</button>
{error && <p>{error}</p>}
</div>
)
}
React 19에서의 개선: useTransition과 Action
React 19에서는 비동기 전환(async transitions)을 사용하여 pending states, error, forms, optimistic updates를 자동으로 처리할 수 있습니다.
아래는 useTransition을 활용한 개선된 방식입니다.
function UpdateName() {
const [name, setName] = useState("");
const [error, setError] = useState(null);
const [isPending, setIsPending] = useTransition();
const handleSubmit = () => {
startTransition(async () => {
const error = await updateName(name); // APU 호출
if (error) {
setError(error); // 에러 처리
return;
}
redirect("/path"); // 성공 시 리다이렉션
})
}
return (
<div>
<input value={name} onChange={(event) => setName(event.target.value)} />
<button onClick={handleSubmit} disabled={isPending}>Update</button>
{error && <p>{error}</p>}
</div>
)
}
useTransition의 동작
1. 즉각적 대기 상태 설정: startTransition 내의 작업이 시작되면, isPending이 자동으로 true로 설정됩니다.
2. 대기 상태 종료: 작업이 완료되거나 전환이 끝나면 isPending이 자동으로 false로 전환됩니다.
3. UI의 응답성 유지: 대기 상태 동안에도 UI는 상호작용이 가능합니다.
Action이란?
Action은 React 19에서 비동기 전환을 사용하는 함수로, 다음 작업을 자동으로 처리합니다.
1. 대기 상태 관리: 요청 시작 시 isPending을 활성화하고 요청이 완료되면 비활성화
2. 낙관적 업데이트 지원: useOptimistic을 통해 요청 중 예상 결과를 미리 UI에 표시
3. 에러 처리: 요청 실패 시 에러 경계를 표시하고, 낙관적 업데이트를 원래 상태로 복구
4. 폼 제출 관리: <form>의 action 속성에 함수를 전달하면 폼 제출 및 상태 리셋이 자동으로 처리됩니다.
React 19는 Actions의 기능을 확장하여 다음과 같은 새로운 도구를 도입합니다.
function ChangeName({ name, setName }) {
const [error, submitAction, isPending ] = useActionState(
async (previousState, formData) => {
const error = await updateName(formData.get("name"));
if (error) {
reteurn error;
}
redirect("/path");
return null;
},
null,
);
return (
<form action={submitAction}>
<input type="text" name="name" />
<button type="submit" disabled={isPending}>Update</button>
{error && <p>{error}</p>}
</form>
)
}
새로운 Action의 기능들에 대해서 하나씩 살펴보겠습니다.
1) New hook: useActionState
const [error, submitAction, isPending] = useActionState(
async (previousState, newName) => {
const error = await updateName(newName);
if (error) {
// You can return any result of the action.
// Here, we return only the error.
return error;
}
// handle success
return null;
},
null,
);
- Actions와 관련된 일반적인 사용 사례를 간소화하기 위해 도입된 새로운 Hook입니다.
- 비동기 요청과 대기 상태, 에러 처리 등을 자동으로 관리합니다.
2) React DOM: <form> Actions
React DOM은 React 19에서 새롭게 추가된 <form> 관련 기능과 Actions를 통합했습니다.
이제 <form>, <input>, <button> 요소의 action 및 formAction 속성에 함수를 직접 전달할 수 있습니다.
<form action={actionFunction}>
<form> Action이 성공하면, React는 비제어 컴포넌트에 대해 폼을 자동으로 초기화합니다.
필요한 경우 새로운 requestFormReset API를 사용하여 form을 수동으로 초기화할 수 있습니다.
3) React DOM: New hook: useFormStatus
useFormStatus는 <form> 상태 정보를 간편하게 가져올 수 있는 새로운 Hook입니다.
디자인 시스템에서는 컴포넌트가 자신이 포함된 <form>에 대한 정보를 필요로 하는 경우가 많습니다.
기존에는 이러한 정보를 자식 컴포넌트로 전달하기 위해 props drilling이나 Context API를 사용해야 했습니다.
React 19에서는 이러한 과정을 간소화하기 위해 useFormStatus Hook을 도입했습니다.
import {useFormStatus} from 'react-dom';
function DesignButton() {
const {pending} = useFormStatus();
return <button type="submit" disabled={pending} />
}
useFormStatus의 주요 특징
1. form 상태 읽기
- useFormStatus는 부모 <form>의 상태를 Context 없이 읽을 수 있습니다.
- 대기 상태(pending), 에러 등 <form>에서 관리하는 상태를 쉽게 확인 가능합니다.
2. Context-like 동작
- useFormStatus는 <form>이 마치 Context Provider처럼 동작하도록 만듭니다.
- 컴포넌트 구조와 관계없이 form 상태를 공유할 수 있습니다.
3. 디자인 시스템에서 유용
- 버튼, input 등의 공통 컴포넌트를 작성할 때, props를 거치지 않고 form 상태를 바로 활용 가능합니다.
4) New hook: useOptimistic
데이터 변경 작업(예: API 요청) 중 흔히 사용되는 UI 패턴 중 하나는 최종 상태를 낙관적으로 미리 표시하는 것입니다.
ㄲReact 19에서는 이러한 낙관적 업데이트를 더 쉽게 구현할 수 있도록 useOptimistic이라는 새로운 Hook을 도입했습니다.
function ChangeName({ currentName, onUpdateName }) {
const [optimisticName, setOptimisticName] = useOptimistic(currentName);
const submitAction = asycn formData => {
const newName = formData.get("name");
setOptimisticName(newName);
const updatedName = await updateNAme(newName);
onUpdateName(updatedName);
};
return (
<form action={submitAction}>
<p>Your name is: {optimisticName}</p>
<p>
<label>Change Name:</label>
<input
type="text"
name="name"
disabled={currentName !== optimisticName}
/>
</p>
</form>
)
}
useOptimistic Hook의 동작
- 비동기 요청(updateName)이 진행 중일때, 낙관적 상태(optimisticName)가 즉시 렌더링 됩니다.
- 요청이 완료되거나 실패하면, React는 자동으로 현재 상태(currentName)로 전환합니다.
New API: use
React 19에서는 렌더링 중 리소스를 읽을 수 있는 새로운 API인 use를 도입했습니다.
use를 사용하면 Promise를 읽을 수 있으며, React는 Promise가 해결될 때까지 Suspense 상태로 대기합니다.
import {use} from 'react';
function Comments({ commnetsPromise }) {
// `use` will suspensed until the promise resolves.
const comments = use(commentsPromise);
return comments.map(comment => <p key={comment.id}>{comment}</p>);
}
function Page({commentsPromise}) {
// When `use` suspends in Comments,
// this Suspense boundary will be shown.
reteurn (
<Suspense fallback={<div>Loading...</div>}>
<Comments commentsPromise={commentsPromise} />
</Suspense>
)
}
렌더링 중에 생성된 Promise에 대한 use API는 렌더링 중에 생성된 Promise를 지원하지 않습니다. 만약 렌더링 중 생성된 Promise를 use에 전달하려고 시도한다면, React는 다음과 같은 경고 메시지를 표시합니다.

제한의 이유
1. React의 렌더링 흐름 유지
- 렌더링 중 Promise를 생성하면 렌더링마다 새로운 Promise가 생성되어 React의 렌더링 흐름이 불안정해질 수 있습니다.
2. 중복 요청 방지
- 같은 데이터에 대한 반복 요청을 방지하기 위해, use는 캐싱된 Promise만 지원합니다.
렌더링 중 Promise를 사용하려면, Suspense를 지원하는 라이브러리 또는 프레임워크에서 제공하는 캐싱된 Promise를 전달해야 합니다.
import {use} from 'react';
import ThemeContext from './ThemeContext'
function Heading({children}) {
if (children == null) {
return null;
}
// This would not work with useContext
// because of the early return
const theme = use(ThemeContext);
return (
<h1 style={{color: theme.color}}>
{children}
</h1>
)
}
use API 호출 규칙
- 렌더링 중에만 호출 가능: use는 다른 React Hook(useSTate, useEffect 등)처럼 렌더링 중에만 호출할 수 있습니다.
- 조건부 호출 가능: 기존 Hook들과 달리, use는 조건문 내에서 호출할 수 있습니다.(예: 특정 조건에 따라 Context나 Promise를 읽기 위해 호출)
New React DOM Static APIs
정적 사이트 생성을 위한 새로운 API
React 19에서는 정적 사이트 생성(Static Site Generation, SSG)을 지원하기 위해 React DOM에 두 가지 새로운 API를 추가했습니다.
1. prerender
2. prerenderToNodeStream
이 새로운 API들은 기존의 renderToString을 개선하여, 정적 HTML을 생성하기 전에 데이터를 로드할 수 있도록 지원합니다.
Node.js Streams 및 Web Streams와 같은 스트리밍 환경에서 동작하도록 설계되었습니다. 예를 들어, Web Stream 환경에서 REact 트리를 정적 HTML로 프리렌더링할 수 있습니다.
import { prerender } from 'react-dom/static';
async function handler(request) {
const {prelude} = await prerender(<App />, {
bootstrapScripts: ['/main.js']
});
return new Response(prelude, {
headers: {'context-type': 'text/html' },
});
}
Prerender API는 정적 HTML 스트림을 반환하기 전에 모든 데이터를 로드할 때까지 대기합니다.
스트림은 문자열로 변환하거나 스트리밍 응답으로 전송할 수 있습니다.
Prerender API는 콘텐츠가 로드되는 즉시 스트리밍하는 것을 지원하지 않으며, 이는 기존의 React DOM 서버 렌더링 API에서 지원됩니다.
React Server Component
Server Components
서버 컴포넌트는 번들링 전에, 클라이언트 애플리케이션이나 SSR 서버와는 분리된 환경에서 컴포넌트를 사전에 렌더링할 수 있는 새로운 옵션입니다.
이 분리된 환경이 React 서버 컴포넌트에서 말하는 "서버"를 의미합니다.
서버 컴포넌트는 빌드 시 CI 서버에서 한번 실행되거나, 웹 서버를 통해 요청마다 실행될 수 있습니다.
React 19에서는 Canary 채널에서 포함된 모든 React 서버 컴포넌트 기능이 포함되어 있습니다.
이는 서버 컴포넌트를 사용하는 라이브러리가 이제 React 19를 peer denpendancy로 설정할 수 있으며, Full-stack React 아키텍처를 지원하는 프레임워크에서 react-server 내보내기 조건으로 사용할 수 있음을 의미합니다.
React 19 서버 컴포넌트는 안정적이며, 주요 버전 간에는 호환성을 유지합니다. 그러나 서버 컴포넌트 번들러 또는 프레임워크를 구현하는 데 사용되는 기본 API는 버전관리규칙을 따르지 않으며, React 19.x의 소규모 업데이트 간에도 변경될 가능성이 있습니다.
Server Actions
서버 액션은 클라이언트 컴포넌트에서 서버에서 실행되는 비동기 함수를 호출할 수 있게 해줍니다.
"use server" 지시어
서버 액션을 정의할 때, "use server" 지시어를 사용하면 프레임워크가 서버 함수의 참조를 자동을 생성하여 클라이언트 컴포넌트에 전달합니다. 클라이언트에서 해당 함수를 호출하면, React가 서버로 요청을 전송해 함수를 실행하고 결과를 반환합니다
서버 컴포넌트와의 차이점
"use server" 지시어는 서버 액션에서만 사용되며, 서버 컴포넌트를 나타내는 지시어는 없습니다. 이는 서버 컴포넌트와 서버 액션을 혼동하기 쉬운 점을 방지하기 위한 설명입니다.
서버 액션의 활용
서버컴포넌트에서 서버 액션을 정의한 후, 클라이언트 컴포넌트의 prosps로 전달합니다.
서버 액션을 클라이언트 컴포넌트로 가져와 사용할 수도 있습니다.
React 19의 개선사항
props로써 ref
React 19의 새로운 기능
React 19부터, 함수 컴포넌트에서도 ref를 props로 직접 전달할 수 있었습니다.
function MyInput({ placeholder, ref }) {
return <input placeholder={placeholder} ref={ref} />;
}
// 사용 예시
<MyInput ref={ref} />
기존 방식과의 차이점
- 이전에는 forwardRef를 사용해야만 함수 컴포넌트에 ref를 전달할 수 있었습니다.
- 이제는 forwardREf가 필요하지 않으며, React가 자동으로 ref를 props로 처리합니다.
Hydration 오류에 대한 개선사항
React 19에서의 Hydration 오류 보고 개선
React DOM에서는 Hydration 오류에 대한 보고 방식을 개선했습니다.
기존에는 개발(DEV) 환경에서 다음과 같은 방식으로 여러 오류가 로그에 기록되었습니다.

이제 단일 메시지로 서버와 클라이언트 간의 불일치를 명확히 보여줍니다.

Provider로써 <Context>
React 19에서 <Context.Provider> 대신 <Context>를 바로 렌더링할 수 있습니다.
const ThemeContext = createContext("");
function App({children}) {
return (
<ThemeContext value="dark">
{children}
</ThemeContext>
)
}
React 19에서는 <Context>를 사용하여 Context 값을 제공할 수 있습니다. React 팀은 기존 <Context.Provider>를 사용하는 코드를 <Context>로 변환할 수 있는 codemod(자동코드변환도구)를 제공할 예정입니다.
Ref를 위한 클린업 함수 지원
이제는 React의 ref 콜백에서 클린업 함수를 반환할 수 있습니다.
<input
ref={(ref) => {
// ref created
// NEW: return a cleanup funciton to reset
// the ref when element is removed from DOM
return () => {
// ref cleanup
};
}}
/>
새로운 동작
1. 클린업 함수 호출
- 컴포넌트가 언마운트되거나, DOM에서 요소가 제거될 때 React가 ref 콜백에서 반환된 클린업 함수를 호출합니다.
2. 적용 대상
- DOM, ref, 클래스 컴포넌트 ref, useImperativeHandle로 생성된 ref 모두 지원
변경 사항
- 이전 동작
- React는 컴포넌트가 언마운트될 때 ref 콜백에서 null을 전달했습니다.
- 새로운 동작
- 클린업 함수가 반환되면, React는 더 이상 null을 전달하지 않습니다.
- 대신 반환된 클린업 함수를 호출합니다.
Ref 클린업 함수 도입에 따른 TypeScript와의 호환성
- Ref 클린업 함수의 도입으로 인해, ref 콜백에서 다른 값을 반환하는 코드는 이제 TypeScript에서 거부됩니다.용되지 않습니다.
- 이는 TypeScript가 반환된 값이 클린업 함수인지, 단순 반환값인지 구분하지 못하기 때문입니다.
// 잘못된 코드
// 암시적 반환으로 인해 TypeScript에서 문제가 발생할 수 있습니다.
// 아래 코드는 HTMLDivElement 인스턴스를 반환하며, TypeScript는 이를 클린업 함수로 오인할 수 있습니다.
<div ref={(current) => (instance = current)} />
// 수정된 코드
// 암시적 반환을 제거하고 명시적으로 작업을 처리해야 합니다.
<div ref={(current) =>{ instance = current }} />
React 팀은 이 패턴을 자동으로 변환할 수 있는 codemod 도구를 제공합니다.
- 도구 이름: no-implicit-ref-callback-return
- 이 도구는 암시적 반환을 명시적 코드로 수정하여 TypeScript와의 호환성을 보장합니다.
useDefferredValue의 초기값 옵션
새로운 기능: useDefferredValue의 initialValue 옵션
React는 useDeferredValue Hook에 초기값 옵션을 추가했습니다.
function Search({ deferredValue }) {
// 초기 렌더링 시 값은 ''입니다.
// 이후 deferredValue를 사용하여 백그라운드에서 리렌더링이 예약됩니다.
const value = useDeferredValue(deferredValue, '');
return <Results query={value} />
}
동작 방식
1. 초기 렌더링
initialValue로 지정된 값('' 등)이 컴포넌트의 초기 렌더링 시 반환됩니다.
2. 백그라운드 리렌더링
React는 deferredValue를 사용하여 백그라운드에서 리렌더링을 예약합니다.
적용 시나리오
데이터 로딩이나 입력 값 처리 중 초기 렌더링 시 임시값을 보여주고, 값이 준비되면 최종 값으로 업데이트하는 경우에 유용합니다.
문서 Metadata 지원
HTML에서의 문서 메타데이터
HTML에서는 <title>, <link>, <meta>와 같은 문서 메타데이터 태그는 문서의 <head> 섹션에 위치해야 합니다.
React에서는 이러한 메타데이터를 결정하는 컴포넌트가 <head>를 렌더링하는 위치와 멀리 떨어져 있거나, <head>를 렌더링하지 않을 수도 있습니다.
과거에는 다음과 같은 방법으로 메타데이터를 처리해야 했습니다.
- 수동 삽입: useEffect를 사용해 직접 <head>에 추가
- 라이브러리 사용: react-helmet과 같은 외부 라이브러리를 활용
- 서버 렌더링 시 세심한 관리 필요
React 19의 새로운 기능
React 19에서는 문서 메타데이터 태그를 컴포넌트 내에서 네이티브로 렌더링할 수 있는 기능을 추가했습니다.
function BlogPost({ post }) {
return (
<article>
<h1>{post.title}</h1>
<title>{post.title}</title>
<meta name="author" content="Josh" />
<link rel="author" href="https://twitter.com/joshcstory/" />
<meta name="keywords" content={post.keywords} />
<p>
Eee equals em-see-squared...
</p>
</article>
)
}
새로운 동작
React는 컴포넌트를 렌더링할 때 <title>, <link>, <meta> 태그를 감지하고, 자동으로 <head> 섹션으로 이동(호이스트)합니다.
주요 특징
1. 클라이언트 전용 애플리케이션 지원
- <head>를 렌더링하지 않아도 메타데이터 태그로 처리
2. 스트리밍 SSR 및 서버 컴포넌트 지원
- 서버 렌더링 환경에서도 메타데이터가 자동으로 <head>에 포함됩니다.
단순한 사용 사례에서는 문서 메타데이터를 태그로 직접 렌더링하는 방식이 적합할 수 있습니다.
하지만 라이브러리는 다음과 같은 강력한 기능을 제공하므로 여전히 유용할 수 있습니다.
- 일반 메타데이터 덮어쓰기
- 현재 경로에 따라 일반적인 메타데이터를 특정 메타데이터로 동적으로 대체합니다.
- 프레임워크와의 통합
- react-helmet과 같은 라이브러리는 메타데이터 태그를 더 쉽게 관리하고 프레임워크와 통합할 수 있도록 도와줍니다.
스타일시트 지원
기존 문제
- 외부 링크 스타일시트(<link ref="stylesheet">)와 인라인 스타일시트(<style>...</style>)는 스타일 우선순위 규칙에 따라 DOM에서 정확한 위치에 배치해야 합니다.
- 스타일시트를 컴포넌트 내부에서 조합 가능하도록 관리하는 것은 어렵습니다.
결과적으로, 사용자들은 스타일을 컴포넌트와 멀리 떨어진 곳에서 로드하거나, 복잡성을 처리하기 위해 스타일 라이브러리를 사용하는 경우가 많습니다.
React 19에서의 개선 사항
React 19는 스타일시트 관리를 간소화하고, 클라이언트의 동시 렌더링 및 서버의 스트리밍 렌더링과 더 깊게 통합합니다.
우선 순위 관리
React에 스타일시트의 우선순위를 지정하면, DOM에 올바른 순서로 삽입되며, 해당 스타일 규칙을 사용하는 콘텐츠가 표기되기 전에 스타일시트가 로드됩니다.
function ComponentOne() {
return (
<Suspense fallback="loading...">
<link rel="stylesheet" href="foo" precedence="default" />
<link rel="stylesheet" href="bar" precedence="high" />
<article class="foo-class bar-class">
{...}
</article>
</Suspense>
)
}
function ComponentTwo() {
return (
<div>
<p>{...}</p>
<link rel="stylesheet" href="baz" precedence="default" /> {/* foo와 bar 사이에 삽입 */}
</div>
)
}
서버 사이드 렌더링
- React가 서버에서 HTML을 생성할 때, 필요한 스타일시트 파일을 <head> 태그에 넣어줍니다.
- 이렇게 하면, 브라우저 화면을 표시하기 전에 스타일을 모두 로드하므로 깜빡임 없이 완벽한 화면을 볼 수 있습니다.
- 만약 스타일시트를 나중에 발견했더라도, React는 Suspense라는 대기 영역을 사용해서, 그 스타일이 적용되기 전에는 화면을 보여주지 않도록 관리합니다.
클라이언트 사이드 렌더링
- React가 브라우저에서 화면을 그릴 때, 새로 필요한 스타일스트가 모두 로드될 때까지 기다립니다.
- 그리고 앱의 여러 곳에서 같은 스타일시트를 사용하더라도, React는 한 번만 스타일시트를 로드해서 불필요한 중복을 방지합니다.
function App() {
return <>
<ComponentOne />
...
<ComponentOne /> // won't lead to a duplicate styleshht link in the DOM
</>
}
스타일시트를 더 효율적으로 관리할 수 있음
- 기존에는 스타일시트를 따로 관리하고 로드해야 해서 어떤 스타일이 어디에 필요한지 파악하기 어려웠습니다.
- 이제 React는 스타일시트를 컴포넌트와 함께 위치시킬 수 있도록 도와줍니다. 이렇게 하면 컴포넌트가 필요한 스타일만 로드하게 되어 코드 관리가 훨씬 쉬워집니다.
스타일 라이브러리도 이 기능을사용할 수 있음
- 직접 스타일시트를 관리하지 않더라도, 사용 중인 스타일 라이브러리나 번들러(예: Webpack, Vite)가 이 새로운 기능을 채택하면 동일한 이점을 누릴 수 있습니다.
- 즉, 도구가 업그레이드되면 자동으로 더 효율적인 관리를 경험하게 됩니다.
Asycn scripts 지원
HTML 스크립트 로드 방식의 문제
- 일반적인 <script> 태그와 <script async> 태그는 문서에 작성된 순서대로 로드됩니다.
- 이런방식은 컴포넌트 구조가 깊어질수록 필요한 스크립트를 로드하는 위치를 관리하기 어려워집니다.
- 반면, <script async> 태그는 순서를 무시하고, 스크립트를 아무 순서나 로드합니다. 이로 인해 관리가 더 복잡해질 수 있습니다.
React 19의 개선 사항
- 이제 React 19에서는 비동기 스크립트를 컴포넌트 트리 어디에서든 렌더링 할 수 있습니다.
- 필요한 스크립트를 해당 컴포넌트 바로 근처에서 정의할 수 있기 때문에 로드 위치를 따로 이동하거나 중복된 스크립트를 관리할 필요가 없습니다.
function MyComponent() {
return (
<div>
<script asycn={true} scr="..." />
)
}
function App() {
}
스크립트 중복 로드 방지
- React는 async script를 컴포넌트에서 여러 번 렌더링하더라도, 해당 스크립트를 한 번만 로드하고 실행합니다.
- 즉, 동일한 스크립트를 여러 컴포넌트가 사용해도 중복 로드 걱정을 하지 않아도 됩니다.
서버 사이드 렌더링(SSR)에서의 처리
- 서버에서 렌더링할 때, React는 비동기 스크립트를 <head>에 포함시킵니다.
- 그러나 스타일시트, 폰트, 이미지 로드와 같은 화면 표시를 막는 중요한 리소스 뒤에 스크립트를 우선순위로 배치하여 성능 최적화를 돕습니다.
리소스 사전로드 지원
리소스 사전로드가 중요한 이유
- 페이지가 처음 로드되거나, 클라이언트 측에서 업데이트될 때 브라우저가 나중에 필요한 리소스를 미리 알게 하면, 로딩 속도가 빨라지고 페이지 성능이 크게 개선됩니다.
- 즉, 필요한 리소스를 늦게 로드하지 않고, 미리 준비해서 화면이 더 빨리 표시되도록 돕습니다.
React 19의 새로운 기능
- React 19에서는 브라우저 리소스를 로드하거나 사전로드하는 것을 쉽게 만들기 위해 새로운 API들을 제공합니다.
- 이를 통해, 효율적이지 못한 리소스 로딩으로 인해 사용자 경험이 저하되는 문제를 해결할 수 있습니다.
import { prefetchDNS, preconnect, preload, preinit } from 'react-dom'
function MyComponent() {
preinit('https://.../path/to/some/script.js', {as: 'script' }) // loads and executes this script eagerly
preload('https://.../path/to/font.woff', { as: 'font' }) // preloads this font
preload('https://.../path/to/stylesheet.css', { as: 'style' }) // preloads this stylesheet
prefetchDNS('https://...') // when you may not actually request anything from this host
preconnect('https://...') // when you will request something but aren't sure what
}
<!-- the above would result in the following DOM/HTML -->
<html>
<head>
<!-- links/scripts are prioritized by their utility to early loading, not call order -->
<link rel="prefetch-dns" href="https://...">
<link rel="preconnect" href="https://...">
<link rel="preload" as="font" href="https://.../path/to/font.woff">
<link rel="preload" as="style" href="https://.../path/to/stylesheet.css">
<script async="" src="https://.../path/to/some/script.js"></script>
</head>
<body>
...
</body>
</html>
초기 페이지 로드 최적화
- React 19의 새로운 API는 스타일시트를 로드하면서 추가로 필요한 리소스(예: 폰트)를 나에 찾는 것이 아니라, 미리 찾아서 로드하도록 만들어 초기 페이지 로드 속도를 더 빠르게 합니다.
클라이언트 업데이트 속도 향상
- 예상되는 페이지 이동(네비게이션)에서 필요한 리소스를 미리 가져오기(prefetching) 기능을 제공합니다.
- 예를 들어, 사용자가 링크를 클릭하거나 심지어 마우스를 링크 위에 올려놓는 것만으로도, 필요한 리소스를 미리 로드하여 더 빠르게 화면이 전환됩니다.
Third-part scripts 및 extensions의 호환성
React와 외부 스크립트/확장 프로그램의 충돌 문제 해결
- 서버에서 생성된 HTML과 클라이언트에서 렌더링된 React 요소가 일치하지 않으면, React는 클라이언트에서 재랜더링을 통해 문제를 해결합니다.
- 이전에는 서드파티 스크립트나 브라우저 확장 프로그램이 삽입된 요소 때문에 불일치 오류가 발생할 수 있었습니다.
React 19의 개선 사항
- 이제 <head>와 <body> 에 서드파티 스크립트나 확장 프로그램이 추가한 예상치 못한 태그를 무시하고, 이를 건너 뜁니다.
- React가 전체 문서를 다시 렌더링해야 하는 경우에도, 서드파티 스크립트와 확장 프로그램이 추가한 스타일시트는 삭제되지 않고 그대로 유지됩니다. (...무슨말이지)
더 나은 오류보고
React의 이전 오류 처리 문제
- React 18에서는 렌더링 중 발생한 오류를 Error Boundary가 잡으면 다음과 같은 문제가 있었습니다.
- React가 오류를 두번 던짐:
- 첫번째는 원래 발생한 오류
- 두번째는 React가 자동 복구에 실패했을 때 다시 던지는 오류
- console.error를 호출하여 오류 위치 정보를 출력
- React가 오류를 두번 던짐:
React 19의 개선 사항
- React 19에서는 이러한 중복된 오류 처리를 제거하고, 더 간단하고 직관적인 방식으로 오류를 다룹니다.
- caught error와 uncaught error를 처리할 수 있는 새로운 옵션도 제공됩니다.

React 19에서는 오류 정보를 한 번에 제공하여 디버깅을 더 쉽고 효율적으로 만듭니다.

React 19에서는 오류를 더 잘 처리할 수 있도록 새로운 두가지 옵션을 추가했습니다. 기존의 onRecoverableError와 함께 사용ㅎ면 더욱 유연한 오류 처리가 가능합니다.
새로운 옵션 설명
- onCaughtError
- onUncaughtError
- onRecoverableError(기존 옵션)
- React가 오류를 자동 복구했을 때 호출됩니다.
- 예: 클라이언트-서버 간 미묘한 차이로 발생하는 오류를 복구한 경우
Custom 요소 지원
- React 19는 Custom Elements를 완전히 지원하며, 관련 테스트를 모두 통과했습니다.
- 이전 React 버전에서는 Custom Elements 사용이 어려웠습니다. 이유는 React가 인식하지 못하는 props를 속성(attributes)으로 처리했기 때문입니다.이제 React 19는 더 나은 전략으로 Custom Elements와 호환됩니다.
React 19의 새로운 처리 전략
서버 사이드 렌더링(SSR)
- props가 문자열, 숫자 같은 원시값이거나 true일 경우, 이를 속성으로 렌더링합니다.
- props가 객체, 심볼, 함수처럼 비원시값이거나 false일 경우, 렌더링하지 않고 생략합니다.
클라이언트 사이드 렌더링(CSR)
- props가 Custom Element의 속성(property)과 일치하면 이를 속성(property)으로 설정합니다.
- 그렇지 않으면 속성으로 설정합니다.