React 19 Beta
React 19 베타버전이 4월 25일, React Team으로부터 공개됐습니다. npm에서도 다운로드 받을 수 있습니다.
뭐가 새롭게 등장했을까?
Actions
React에서 흔하게 데이터 mutation과 응답 결과를 state에 업데이트하는 과정이 있었습니다. 예를 들어, 유저가 폼을 제출해서 API Request를 보내고 응답 결과를 받을 때 과거에는 states, error, optimistic updates 그리고 sequential requests를 직접 해야했습니다.
// Before Actions
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>
);
}
리액트 19에서 states, error, optimistic updates 그리고 form을 자동으로 처리하기 위해 transition에 async function을 지원합니다. 예를 들어, useTransition을 사용할 수 있습니다.
// Using pending state from Actions
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>
);
}
async transition이 isPending을 시작하자마자 true로 바꾸고, 비동기 요청을 하고 변경이 끝남과 동시에 isPending을 false로 바꿉니다. 해당 기능을 통해 데이터가 변화하는 동안 UI를 interactive하고 responsive하게 만들 수 있습니다.
위에서 언급된 네 가지(Pending states, Optimitic updates, Error Handling, Forms)를 자동으로 처리할 때 도움이 되는 새로운 훅들이 등장했습니다.
신규 훅
useActionState가 신규 훅으로 추가됐습니다. React19을 이용하면 위의 예제를 다음과 같이 단순화할 수 있습니다. form을 사용한다면 startTransition을 대신해서 useActionState를 사용하면 useTransition에서 제공하는 pending 뿐만 아니라 폼에 필요한 action과 error 그리고 마지막 결과를 data로 return합니다.
// Using <form> Actions and useActionState
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 (
<form action={submitAction}>
<input type="text" name="name" />
<button type="submit" disabled={isPending}>Update</button>
{error && <p>{error}</p>}
</form>
);
}
form 태그에도 action이 추가됐습니다. useActionState에서 제공하는 submitAction을 넘겨주면 input, button 요소들을 자동으로 submit할 수 있습니다.
useFormStatus훅이 추가되어 부모 컴포넌트로와 자식 컴포넌트가 분리되어 있더라도 { pending, data, method, action } 을 해당 훅으로부터 props drilling 없이 접근할 수 있습니다.
import { useFormStatus } from "react-dom";
import action from './actions';
function Submit() {
const status = useFormStatus();
return <button disabled={status.pending}>Submit</button>
}
export default function App() {
return (
<form action={action}>
<Submit />
</form>
);
}
또 다른 흔하게 볼 수 있는 경우는, async request가 일어나는 동안 사용자에게 mutation이 성공된 최종 결과를 노출하는건데 새로 등장한 useOptimistic을 통해 성공된 결과를 async request가 일어나는 동안 미리 변경해주고 만약 실패했다면 원래 값으로 돌리는 훅이 등장했습니다.
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>
);
}
과거 Next 13 관련해서 포스트했을때 보였던 promise 또는 context를 resolve하는데 도움을 주는 use훅 또한 소개됐습니다. 다른 훅들과 다르게 반복문이나 조건문에서 사용할 수 있는게 특징입니다. Promise 객체와 함께 사용될 때는, Suspense와 error boundaries와 함께 사용할수 있습니다.
- 반드시 컴포넌트나 훅 안에서 사용될 수 있습니다.
- 서버 컴포넌트에서 데이터를 가져올 때는, async/await를 사용하는게 좋습니다. async/await은 await이 호출되는 시점에 렌더링하는 반면, use는 데이터요소가 다 resolve 되면 컴포넌트 re-render가 발생합니다.
- Promise를 생성할때는 클라이언트보다 서버 컴포넌트에서 생성해서 전달하는게 좋습니다. 클라이언트 컴포넌트에선 렌더링할 때마다 다시 Promise를 만들기 때문에 서버 컴포넌트에서 만드는게 안정적입니다.
React Compiler(React Foget)
모두가 memo, useMemo, useCallback으로부터의 자유를 위해 기다리고 있지만, 이미 예고된 대로 리액트19는 Compiler를 포함하지 않고 있습니다. 이미 instagram.com에 배포되어 사용되고 있지만 빠르면 올해 말에 출시될걸로 보입니다.
'software engineering > frontend' 카테고리의 다른 글
인프런 퇴근길 밋업 - 테스트 코드와 스토리북 (1) | 2024.08.29 |
---|---|
2024 FE conf (3) | 2024.08.26 |
reduce, reduceRight 그리고 functional programming (0) | 2024.04.27 |
Preact 그리고 Signals (0) | 2024.02.14 |
Zustand Persist (부제: localstorage 쉽게 저장하기) (1) | 2024.02.12 |