본 문서는 https://react.dev/blog/2024/12/05/react-19 블로그 글을 ChatGPT를 통해 번역한 내용입니다.
번역에 오역 또는 의역이 있을 수 있습니다.
본문을 확인하고 싶으신 분은 위 사이트를 접속하여 확인 하시기 바랍니다.
React 19의 주요 개선 사항
ref를 prop으로 사용
React 19부터 함수 컴포넌트에서 ref를 prop으로 사용할 수 있습니다:
function MyInput({ placeholder, ref }) {
return <input placeholder={placeholder} ref={ref} />;
}
// 사용 예시
<MyInput ref={ref} />;
- 이점:
새로운 함수형 컴포넌트에서는 더 이상 forwardRef가 필요하지 않습니다. - 변환 지원:
기존의 forwardRef를 사용하는 컴포넌트를 새 방식으로 변환하는 코드를 자동으로 업데이트하는 codemod를 제공할 예정입니다. - 미래 계획:
이후 버전에서 forwardRef는 폐지될 예정입니다. - 제한:
클래스 컴포넌트에 전달된 ref는 컴포넌트 인스턴스를 참조하기 때문에 prop으로 전달되지 않습니다.
하이드레이션 오류에 대한 차이점 로그 제공
React 19에서는 react-dom의 하이드레이션 오류 보고가 개선되었습니다.
기존에는 여러 개의 오류 메시지가 분산되어 출력되었습니다:
Warning: Text content did not match. Server: “Server” Client: “Client”
Warning: An error occurred during hydration. The server HTML was replaced with client content in <div>.
이제는 한 번의 메시지로 불일치에 대한 **차이점(diff)**을 표시합니다:
Uncaught Error: Hydration failed because the server rendered HTML didn’t match the client. This can happen if:
- 서버와 클라이언트 간 조건부 렌더링 (e.g., if (typeof window !== 'undefined')).
- 매번 변하는 데이터 (e.g., Date.now(), Math.random()).
- 사용자 로케일에 따른 날짜 형식.
- 외부 데이터 변경.
- 잘못된 HTML 태그 중첩.
또한 브라우저 확장 프로그램으로 인해 HTML이 변경된 경우도 포함됩니다.
자세한 내용은 하이드레이션 불일치 문서를 참고하세요.
<Context>를 프로바이더로 사용
React 19부터 <Context.Provider> 대신 <Context>를 직접 사용할 수 있습니다:
const ThemeContext = createContext('');
function App({ children }) {
return (
<ThemeContext value="dark">
{children}
</ThemeContext>
);
}
- 변환 지원:
기존 <Context.Provider>를 사용하는 코드를 변환하는 codemod를 제공할 예정입니다. - 미래 계획:
<Context.Provider>는 이후 버전에서 폐지됩니다.
Ref 콜백에 클린업 함수 지원
이제 Ref 콜백에서 클린업 함수를 반환할 수 있습니다:
<input
ref={(ref) => {
// ref 생성 시 실행
return () => {
// ref 정리 시 실행
};
}}
/>
- 작동 방식:
컴포넌트가 언마운트되면 React는 Ref 콜백에서 반환된 클린업 함수를 호출합니다. - 지원 범위:
DOM ref, 클래스 컴포넌트 ref, useImperativeHandle에서 동작합니다. - TypeScript 변경 사항:
Ref 콜백에서 클린업 함수 외의 값을 반환하면 TypeScript가 이를 거부합니다.
예)// 변경 전 <div ref={(current) => (instance = current)} /> // 변경 후 <div ref={(current) => { instance = current; }} />
이러한 패턴은 codemod(no-implicit-ref-callback-return)로 자동 변환할 수 있습니다.
useDeferredValue의 초기값 옵션 추가
React 19에서는 useDeferredValue에 initialValue 옵션이 추가되었습니다:
function Search({ deferredValue }) {
// 초기 렌더링에서는 ''를 반환.
// 백그라운드에서 deferredValue로 다시 렌더링 예약.
const value = useDeferredValue(deferredValue, '');
return <Results query={value} />;
}
- 기능:
초기값을 제공하면, 초기 렌더링에서 해당 값을 반환하고 백그라운드에서 deferredValue로 다시 렌더링합니다.
자세한 내용은 useDeferredValue 문서를 참고하세요.
문서 메타데이터 지원
HTML에서는 <title>, <link>, <meta> 같은 문서 메타데이터 태그가 <head> 섹션에 있어야 합니다. 하지만 React에서는 메타데이터를 결정하는 컴포넌트와 <head>를 렌더링하는 위치가 멀리 떨어져 있거나 <head>를 렌더링하지 않는 경우가 많습니다.
이전에는 react-helmet 같은 라이브러리로 메타데이터를 수동으로 관리하거나, 서버 렌더링 시 특별한 처리가 필요했습니다.
React 19부터는 메타데이터 태그를 컴포넌트에서 직접 작성하면 React가 이를 <head>로 자동으로 이동시킵니다:
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>
);
}
- 동작 방식:
<title>, <meta>, <link> 태그는 자동으로 <head>로 이동합니다. - 장점:
클라이언트 전용 앱, 스트리밍 SSR, 서버 컴포넌트에서도 잘 동작합니다. - 주의 사항:
라우트에 따라 메타데이터를 덮어쓰는 고급 기능이 필요한 경우, 여전히 react-helmet 같은 라이브러리를 사용하는 것이 좋습니다.
스타일시트 지원
React 19에서는 스타일시트를 더 쉽게 관리할 수 있는 기능이 추가되었습니다.
스타일시트 우선순위 관리
스타일시트를 <link rel="stylesheet" href="..." precedence="..." />와 함께 작성하면 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>
);
}
- 서버 렌더링 시, 스타일시트는 <head>에 포함되며 브라우저가 로드 전에 이를 다운로드합니다.
- 클라이언트 렌더링 시, 스타일시트가 로드될 때까지 React는 렌더를 기다립니다.
중복 제거
동일한 스타일시트를 여러 컴포넌트에서 렌더링해도 React는 이를 한 번만 포함합니다.
function App() {
return (
<>
<ComponentOne />
<ComponentOne /> // 중복된 스타일시트 링크는 DOM에 포함되지 않음
</>
);
}
- 라이브러리와의 호환성
스타일 라이브러리나 번들러와 통합하여 더욱 쉽게 스타일을 관리할 수 있습니다.
비동기 스크립트 지원
React 19는 비동기 스크립트(<script async src="...">)를 컴포넌트 내부에서 선언할 수 있도록 개선했습니다:
function MyComponent() {
return (
<div>
<script async={true} src="..." />
Hello World
</div>
);
}
- 중복 제거
동일한 스크립트를 여러 컴포넌트에서 렌더링해도 React는 이를 한 번만 로드합니다. - 서버 렌더링
비동기 스크립트는 <head>에 포함되며 스타일시트, 폰트, 이미지보다 낮은 우선순위를 가집니다.
리소스 사전 로드 지원
React 19는 브라우저 리소스 로딩을 최적화할 수 있는 API를 제공합니다:
import { prefetchDNS, preconnect, preload, preinit } from 'react-dom';
function MyComponent() {
preinit('https://.../script.js', { as: 'script' }); // 스크립트 미리 로드 및 실행
preload('https://.../font.woff', { as: 'font' }); // 폰트 미리 로드
preload('https://.../stylesheet.css', { as: 'style' }); // 스타일시트 미리 로드
prefetchDNS('https://...'); // DNS 프리페치
preconnect('https://...'); // 사전 연결
}
<html>
<head>
<!-- 링크 및 스크립트는 호출 순서가 아닌 초기 로딩에 유용한 순서에 따라 우선순위가 정해집니다 -->
<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>
위 API들은 스타일시트 로딩으로 인해 추가 리소스를 발견하는 과정을 분리하여 초기 페이지 로드 성능을 최적화하는 데 사용할 수 있습니다.
또한, 예상되는 탐색에 필요한 리소스 목록을 미리 가져오거나(prefetching), 클릭 또는 심지어 마우스 오버 시 적극적으로(preloading) 해당 리소스를 로드함으로써 클라이언트 업데이트 속도를 더욱 빠르게 만들 수 있습니다.
- 효과:
리소스 탐색 시간을 단축해 초기 페이지 로딩과 클라이언트 업데이트 성능을 향상시킵니다.
제3자 스크립트 및 확장 프로그램 호환성 개선
React 19는 예상치 못한 태그나 요소가 추가된 경우에도 하이드레이션 오류를 피하도록 개선되었습니다.
Hydration 중에 클라이언트에서 렌더링되는 요소가 서버에서 받은 HTML에 있는 요소와 일치하지 않으면, React는 콘텐츠를 수정하기 위해 클라이언트 측에서 다시 렌더링을 강제합니다. 이전에는 서드파티 스크립트나 브라우저 확장 프로그램이 요소를 삽입한 경우, 불일치 오류와 클라이언트 렌더링이 트리거되었습니다.
React 19에서는 <head>와 <body>에 있는 예상치 못한 태그를 건너뛰어 불일치 오류를 방지합니다. React가 관련 없는 Hydration 불일치로 인해 문서 전체를 다시 렌더링해야 하는 경우, 서드파티 스크립트와 브라우저 확장 프로그램이 삽입한 스타일시트는 그대로 유지됩니다.
에러 보고 개선
React 19는 에러 로깅 방식을 단순화하고 에러 복구를 위한 옵션을 추가했습니다.
- 새로운 에러 처리 옵션:
- onCaughtError: Error Boundary에서 에러를 잡았을 때 호출됩니다.
- onUncaughtError: Error Boundary가 에러를 잡지 못했을 때 호출됩니다.
- onRecoverableError: 에러를 자동으로 복구할 때 호출됩니다.
커스텀 요소 (Custom Elements) 지원
React 19는 커스텀 요소(Custom Elements)를 완벽히 지원하며, Custom Elements Everywhere 테스트를 모두 통과했습니다.
이전 버전에서는 React가 인식하지 못하는 props를 속성(attribute)으로 처리했기 때문에 커스텀 요소를 사용하는 데 어려움이 있었습니다. 그러나 React 19에서는 클라이언트와 서버 사이드 렌더링(SSR) 모두에서 작동하는 속성(Property) 지원이 추가되었습니다.
적용 방식
- 서버 사이드 렌더링(SSR):
커스텀 요소에 전달된 props는 다음과 같은 경우 속성(attribute)으로 렌더링됩니다:- 값이 원시 타입(primitive type)인 경우, 예를 들어 문자열, 숫자, 또는 true.
- 값이 원시 타입이 아닌 경우, 예를 들어 객체, 심볼, 함수, 또는 false, 해당 props는 생략됩니다.
- 클라이언트 사이드 렌더링(CSR):
- 커스텀 요소의 속성과 일치하는 props는 속성(property)으로 설정됩니다.
- 일치하지 않는 props는 속성(attribute)으로 설정됩니다.
더 나은 useReducer 타입 지원
useReducer는 이제 향상된 타입 추론을 제공합니다.
그러나 이는 파괴적인 변경 사항을 필요로 했습니다.
이제 useReducer는 전체 리듀서 타입을 타입 매개변수로 허용하지 않으며, 대신 타입 매개변수를 제공하지 않고 컨텍스트 기반 타입을 사용하는 방법이나, state와 action 타입을 모두 명시하는 방법만 가능합니다.
새로운 모범 사례는 useReducer에 타입 인수를 전달하지 않는 것입니다.
// 이전 방식
useReducer<React.Reducer<State, Action>>(reducer)
// 권장 방식
useReducer(reducer)
이 변경 사항은 모든 경우에 적용되지는 않을 수 있습니다.
예외적인 경우에는, Action을 튜플로 전달하여 상태와 액션을 명시적으로 타입 지정할 수 있습니다
// 이전 방식
useReducer<React.Reducer<State, Action>>(reducer)
// 권장 방식
useReducer<State, [Action]>(reducer)
만약 리듀서를 인라인으로 정의하는 경우, 함수 매개변수에 어노테이션을 추가하는 것을 권장합니다.
// 이전 방식
useReducer<React.Reducer<State, Action>>((state, action) => state)
// 권장 방식
useReducer((state: State, action: Action) => state)
또한, 리듀서를 useReducer 호출 외부로 이동시키는 경우에도 동일한 방식으로 처리해야 합니다.
const reducer = (state: State, action: Action) => state;
'자바스크립트 > React & Next.js' 카테고리의 다른 글
React 19 ( 리액트 19 ) - 신규 기능 (한글) (0) | 2024.12.06 |
---|---|
Cafe24 일반 호스팅에 Next.js ( React ) SSG 배포 (3) | 2024.10.22 |
Next.JS 14 Jotai 사용 시 Detected multiple Jotai instances. 경고 (1) | 2024.01.03 |