본 문서는 https://react.dev/blog/2024/12/05/react-19 블로그 글을 ChatGPT를 통해 번역한 내용입니다.
번역에 오역 또는 의역이 있을 수 있습니다.
본문을 확인하고 싶으신 분은 위 사이트를 접속하여 확인 하시기 바랍니다.
React 19의 새로운 기능: Actions
React 앱에서 자주 사용되는 시나리오 중 하나는 데이터를 변경하고 그에 따라 상태를 업데이트하는 것입니다. 예를 들어, 사용자가 이름을 변경하는 폼을 제출하면 API 요청을 수행한 후 응답을 처리해야 합니다. 이전에는 대기 상태, 오류 처리, 낙관적 업데이트(optimistic update), 순차적 요청 등을 수동으로 처리해야 했습니다.
이전 방식: useState를 사용한 상태 관리
아래는 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);
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의 새로운 Actions
React 19에서는 대기 상태, 오류 처리, 폼 관리, 낙관적 업데이트를 자동으로 처리할 수 있도록 전환(Transitions)에서 비동기 함수 사용을 지원합니다.
아래는 useTransition을 사용해 대기 상태를 처리하는 예제입니다:
function UpdateName() {
const [name, setName] = useState("");
const [error, setError] = useState(null);
const [isPending, startTransition] = useTransition();
const handleSubmit = () => {
startTransition(async () => {
const error = await updateName(name);
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>
);
}
Actions의 주요 기능
- 대기 상태(pending state): 요청 시작 시 isPending이 true로 설정되며, 요청이 완료되면 자동으로 false로 전환됩니다.
- 낙관적 업데이트: 새로운 useOptimistic 훅을 지원하여 요청 중에도 사용자에게 즉각적인 피드백을 제공합니다.
- 오류 처리: 요청 실패 시 오류 경계(Error Boundary)를 표시하고, 낙관적 업데이트를 원래 상태로 되돌립니다.
- 폼 처리: <form> 요소에서 action 및 formAction 속성에 함수를 전달할 수 있습니다. 이 함수들은 Actions를 기본적으로 사용하며, 제출 후 폼을 자동으로 초기화합니다.
더 간단해진 폼 처리
React 19에서 위 코드는 다음과 같이 단순화될 수 있습니다:
function ChangeName({ name, setName }) {
const [error, submitAction, isPending] = useActionState(
async (previousState, formData) => {
const error = await updateName(formData.get("name"));
if (error) {
return 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>
);
}
새로운 훅: useActionState
Actions를 쉽게 처리하기 위해 React 19는 useActionState 훅을 도입했습니다.
const [error, submitAction, isPending] = useActionState(
async (previousState, newName) => {
const error = await updateName(newName);
if (error) {
// 액션 결과로 반환될 값. 여기서는 오류만 반환.
return error;
}
// 성공 처리
return null;
},
null
);
useActionState는 Action 함수를 받고, 호출할 수 있는 래핑된 Action을 반환합니다. 이 훅은 마지막 Action의 결과를 데이터로 반환하며, Action의 대기 상태를 추적합니다.
주의사항
React.useActionState는 이전 Canary 릴리스에서 ReactDOM.useFormState로 알려졌으며, 이제 이름이 변경되고 useFormState는 사용 중단(deprecated)되었습니다.
참고: #28491에서 더 자세한 정보를 확인할 수 있습니다.
React 19: <form> Actions
React 19에서는 새로운 <form> 기능이 react-dom에 통합되었습니다. 이제 <form>, <input>, <button> 요소의 action 및 formAction 속성에 함수를 전달하여 폼을 자동으로 제출할 수 있습니다.
예제: <form> Actions 사용
<form action={actionFunction}>
- 성공적인 제출 후 동작:
- Uncontrolled 컴포넌트의 경우 React가 자동으로 <form>을 리셋합니다.
- 폼을 수동으로 리셋해야 할 경우 새로운 requestFormReset React DOM API를 호출할 수 있습니다.
추가 정보는 <form>, <input>, <button>에 대한 React DOM 문서를 참조하세요.
React DOM: 새로운 훅 useFormStatus
디자인 시스템에서 자주 사용하는 패턴 중 하나는 <form>의 정보를 컴포넌트로 전달하지 않고 접근하는 것입니다. 이는 일반적으로 Context를 통해 처리하지만, React 19에서는 이를 더 쉽게 처리하기 위해 useFormStatus 훅을 도입했습니다.
useFormStatus 예제
import { useFormStatus } from 'react-dom';
function DesignButton() {
const { pending } = useFormStatus();
return <button type="submit" disabled={pending} />;
}
- useFormStatus는 부모 <form>의 상태를 읽습니다.
- 마치 <form>이 Context 제공자(Provider)처럼 작동합니다.
추가 정보는 React DOM 문서에서 useFormStatus를 확인하세요.
새로운 훅: useOptimistic
데이터 변경 시 비동기 요청 동안 최종 상태를 낙관적으로 보여주는 UI 패턴은 자주 사용됩니다. React 19에서는 이를 더 쉽게 처리하기 위해 useOptimistic 훅을 추가했습니다.
useOptimistic 예제
function ChangeName({ currentName, onUpdateName }) {
const [optimisticName, setOptimisticName] = useOptimistic(currentName);
const submitAction = async (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는 요청이 진행 중일 때 optimisticName을 즉시 렌더링합니다.
- 완료 또는 실패 후 동작: 요청이 완료되거나 실패하면 React는 자동으로 currentName 값으로 돌아갑니다.
추가 정보는 문서에서 확인하세요.
새로운 API: use
React 19에서는 렌더링 시 리소스를 읽기 위한 새로운 API **use**를 도입했습니다.
use로 Promise 읽기
import { use } from 'react';
function Comments({ commentsPromise }) {
// `use`는 Promise가 해결될 때까지 suspend합니다.
const comments = use(commentsPromise);
return comments.map((comment) => <p key={comment.id}>{comment}</p>);
}
function Page({ commentsPromise }) {
return (
<Suspense fallback={<div>Loading...</div>}>
<Comments commentsPromise={commentsPromise} />
</Suspense>
);
}
- use는 Suspense와 함께 작동하여 Promise가 해결될 때까지 대기(suspend)합니다.
주의사항:
- 렌더링 중 생성된 Promise는 지원하지 않음:
렌더링 중 생성된 Promise를 use에 전달하면 React가 경고를 표시합니다.A component was suspended by an uncached promise. Creating promises inside a Client Component or hook is not yet supported...
use로 Context 읽기
use를 사용하면 조건부로 Context를 읽을 수 있습니다. 이는 기존 useContext로는 불가능했던 작업입니다.
예제: 조건부 Context 읽기
import { use } from 'react';
import ThemeContext from './ThemeContext';
function Heading({ children }) {
if (children == null) {
return null;
}
// `useContext`로는 동작하지 않는 조건부 Context 읽기
const theme = use(ThemeContext);
return (
<h1 style={{ color: theme.color }}>
{children}
</h1>
);
}
- use는 렌더링 시 호출되며, 조건부로 호출 가능합니다.
- 향후 use를 활용해 리소스를 소비하는 더 많은 기능이 추가될 예정입니다.
React DOM Static API - Prerender
React 19에서는 정적 사이트 생성을 지원하기 위해 react-dom/static 에 두 가지 새로운 API를 추가했습니다:
- prerender
- prerenderToNodeStream
이 새로운 API는 정적 HTML 생성을 위해 데이터를 로드하는 과정을 기다린 후 결과를 반환하며, 기존의 renderToString보다 향상된 기능을 제공합니다. 특히, Node.js 스트림이나 Web Streams와 같은 스트리밍 환경에서 동작하도록 설계되었습니다.
prerender 예제
다음은 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: { 'content-type': 'text/html' },
});
}
- 작동 방식:
prerender API는 모든 데이터를 로드한 후 정적 HTML 스트림을 반환합니다. - 스트림 지원:
이 API는 스트림을 문자열로 변환하거나 스트리밍 응답으로 전송할 수 있습니다. 그러나 데이터를 로드하는 동안 스트리밍 콘텐츠를 지원하지는 않습니다. (이 기능은 기존 React DOM 서버 렌더링 API에서 지원)
자세한 내용은 React DOM Static API 문서를 참조하세요.
React 서버 컴포넌트 (Server Components)
서버 컴포넌트는 클라이언트 애플리케이션이나 SSR 서버와는 별도의 환경에서 컴포넌트를 사전에 렌더링할 수 있는 새로운 옵션입니다.
- 이 "별도의 환경"이 서버(Server)이며, React Server Components는 이 환경에서 실행됩니다.
- 서버 컴포넌트는 CI 서버에서 빌드 타임에 한 번 실행되거나, 웹 서버를 사용하여 요청별로 실행될 수 있습니다.
React 19의 서버 컴포넌트 주요 특징
React 19는 Canary 채널에 포함된 모든 서버 컴포넌트 기능을 제공합니다. 이를 통해 서버 컴포넌트를 사용하는 라이브러리들은 React 19를 동일한 버전의 의존성(peer dependency)으로 설정할 수 있으며, react-server라는 내보내기 조건을 사용할 수 있습니다. 이는 Full-stack React Architecture를 지원하는 프레임워크와 함께 사용됩니다.
주의사항
React Server Components를 구현하거나 지원하려는 번들러 또는 프레임워크 개발자라면 다음을 알아야 합니다:
React 19의 서버 컴포넌트는 안정적이며, 메이저 버전 간 깨지지 않습니다.하지만 이를 구현하는 데 사용하는 내부 API는 semver를 따르지 않으며, 19.x의 마이너 버전 간 변경 가능성이 있습니다.안정성을 위해 특정 React 버전 또는 Canary 릴리스에 고정(pinning)하는 것을 권장합니다.
추가 정보는 React Server Components 문서에서 확인하세요.
서버 액션 (Server Actions)
서버 액션은 클라이언트 컴포넌트에서 서버에서 실행되는 비동기 함수(async function)를 호출할 수 있게 합니다.
작동 방식:
- "use server" 지시문을 사용하여 서버 액션을 정의하면 프레임워크는 자동으로 서버 함수의 참조를 생성합니다.
- 이 참조는 클라이언트 컴포넌트에 전달되며, 클라이언트에서 해당 함수가 호출되면 React가 서버에 요청을 보내 함수를 실행하고 결과를 반환합니다.
주의사항:
- 서버 컴포넌트는 "use server" 지시문과 무관합니다.
- 일반적으로 서버 컴포넌트는 "use server"로 표시된다고 오해할 수 있지만, 이는 서버 컴포넌트가 아닌 서버 액션에 사용되는 지시문입니다.
- 서버 컴포넌트는 자체 지시문이 필요하지 않습니다.
서버 액션의 사용 예:
- 서버 컴포넌트에서 생성하여 클라이언트 컴포넌트의 props로 전달할 수 있습니다.
- 또는 클라이언트 컴포넌트에서 직접 가져와 사용할 수도 있습니다.
'자바스크립트 > React & Next.js' 카테고리의 다른 글
React 19 ( 리액트 19 ) - 개선 사항 (한글) (1) | 2024.12.06 |
---|---|
Cafe24 일반 호스팅에 Next.js ( React ) SSG 배포 (3) | 2024.10.22 |
Next.JS 14 Jotai 사용 시 Detected multiple Jotai instances. 경고 (1) | 2024.01.03 |