React 19 Beta – React
The library for web and native user interfaces
react.dev
์ผ๋ถ ํด์ ๋ฐ์ท
React 19์ ์๋ก์ด ๊ธฐ๋ฅ
Action
๋ฆฌ์กํธ ์ฑ์ ์ผ๋ฐ์ ์ธ ์ฌ์ฉ ์ฌ๋ก๋ ๋ฐ์ดํฐ ๋ณํ๋ฅผ ์ํํ ๋ค์ ์๋ต์ผ๋ก ์ํ๋ฅผ ์ ๋ฐ์ดํธํ๋ ๊ฒ์ ๋๋ค. ์๋ฅผ ๋ค์ด, ์ฌ์ฉ์๊ฐ ์ด๋ฆ์ ๋ณ๊ฒฝํ๊ธฐ ์ํด ์์์ ์ ์ถํ๋ฉด API ์์ฒญ์ ํ ๋ค์ ์๋ต์ ์ฒ๋ฆฌํฉ๋๋ค. ๊ณผ๊ฑฐ์๋ ๋ณด๋ฅ ์ํ, ์ค๋ฅ, ๋๊ด์ ์ ๋ฐ์ดํธ ๋ฐ ์์ฐจ์ ์์ฒญ์ ์๋์ผ๋ก ์ฒ๋ฆฌํด์ผ ํ์ต๋๋ค.
์๋ฅผ ๋ค์ด usestate์์ ๋ณด๋ฅ ๋ฐ ์ค๋ฅ ์ํ๋ฅผ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
// 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>
);
}
React 19 ์์๋ ๋ณด๋ฅ ์ค์ธ ์ํ, ์ค๋ฅ, ์์ ๋ฐ ๋๊ด์ ์ ๋ฐ์ดํธ๋ฅผ ์๋์ผ๋ก ์ฒ๋ฆฌํ๊ธฐ ์ํด ์ ํ์ Async functions์ ์ฌ์ฉํ๋ ์ง์์ ์ถ๊ฐํ๊ณ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด, '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>
);
}
๋น๋๊ธฐ ์ ํ์ ์ฆ์ isPending ์ํ๋ฅผ True๋ก ์ค์ ํ๊ณ , ๋น๋๊ธฐ ์์ฒญ์ ํ๊ณ , isPending ์ ํ ํ์๋ false๋ก ์ ํํฉ๋๋ค. ์ด๋ฅผ ํตํด ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋๋ ๋์ ํ์ฌ UI์ ๋ฐ์์ฑ๊ณผ ๋ํํ์ ์ ์งํ ์ ์์ต๋๋ค.
๊ด๋ก์ ์ผ๋ก ๋น๋๊ธฐ ์ ํ์ ์ฌ์ฉํ๋ ํจ์๋ฅผ 'Action'์ด๋ผ๊ณ ํ๋ค.
Action์ ์ ์ถ๋ ๋ฐ์ดํฐ๋ฅผ ์๋์ผ๋ก ๊ด๋ฆฌ.
- Pending State: ์์ ์ ์์ฒญ ์์ ์ ์์๋๊ณ ์ต์ข ์ํ ์ ๋ฐ์ดํธ๊ฐ ์ปค๋ฐ๋๋ฉด ์๋์ผ๋ก ์ฌ์ค์ ๋๋ ๋ณด๋ฅ ์ํ๋ฅผ ์ ๊ณต
- Optimistic Updates: ์์ ์ ์๋ก์ด useOptimistic ํ ์ ์ง์ํ๋ฏ๋ก ์์ฒญ์ด ์ ์ถ๋๋ ๋์ ์ฌ์ฉ์์๊ฒ ์ฆ๊ฐ์ ์ธ ํผ๋๋ฐฑ์ ํ์ํ ์ ์์
- Error handling: ์์ ์ ์ค๋ฅ ์ฒ๋ฆฌ๋ฅผ ์ ๊ณตํ๋ฏ๋ก ์์ฒญ์ด ์คํจํ ๋ ์ค๋ฅ ๊ฒฝ๊ณ๋ฅผ ํ์ํ๊ณ , ๋๊ด์ ์ ๋ฐ์ดํธ๋ฅผ ์๋ ๊ฐ์ผ๋ก ์๋์ผ๋ก ๋๋๋ฆด ์ ์์.
- Forms: <form> ์์๋ ์ด์ Action ๋ฐ formAction ์ํ์ ํจ์ ์ ๋ฌ์ ์ง์ํจ. props์ ํจ์๋ฅผ ์ ๋ฌํ๋ฉด action ๊ธฐ๋ณธ์ ์ผ๋ก Actions๊ฐ ์ฌ์ฉ๋๋ฉฐ ์ ์ถ ํ ์๋์ผ๋ก ์์์ด ์ฌ์ค์ ๋จ.
Actions๋ฅผ ๊ธฐ๋ฐ์ผ๋ก React 19์์๋ useOptimistic ๊ณผ Actions์ ์ผ๋ฐ์ ์ธ ์ฌ๋ก๋ฅผ ์ฒ๋ฆฌํ๋ ์๋ก์ด ํ ์ธ React.useActionState๋ฅผ ๋์ ํฉ๋๋ค. React-dom์์๋ ์์์ ์๋์ผ๋ก ๊ด๋ฆฌํ๋ Actions์ ์์์ ์ผ๋ฐ์ ์ธ ์ฌ๋ก๋ฅผ ์ง์ํ๋ useFormStatus๋ฅผ ์ถ๊ฐํ๊ณ ์์ต๋๋ค.
React 19 ์์ ์์ ์๋ ๋ค์๊ณผ ๊ฐ์ด ๋จ์ํํ ์ ์์ต๋๋ค.
// 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>
);
}
New Hook: useActionState
์ผ๋ฐ์ ์ธ ์ฌ๋ก๋ฅผ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์๋๋ก 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
});
useActionState Function("Action")๋ฅผ Pendingํ๊ณ ํธ์ถํ Action์ ๋ฐํํฉ๋๋ค. ์ด๊ฒ์ ์ก์ ์ด ๊ตฌ์ฑ๋๊ธฐ ๋๋ฌธ์ ์๋ํฉ๋๋ค. ๋ํ๋ ์ก์ ์ด ํธ์ถ๋๋ฉด useActionState๋ ์ก์ ์ ๋ง์ง๋ง ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์ดํฐ๋ก, ๋ณด๋ฅ ์ค์ธ ์ก์ ์ ์ํ๋ฅผ Pending์ผ๋ก ๋ฐํํฉ๋๋ค.
์ด์ ์ ์นด๋๋ฆฌ์ ๋ฆด๋ฆฌ์ฆ์์ React.useActionState๋ฅผ ReactDOM.useFormState๋ผ๊ณ ๋ถ๋ ์ง๋ง
FormState๋ผ๋ ์ด๋ฆ์ ๋ณ๊ฒฝํ๊ณ , useFormState๋ฅผ ์ฌ์ฉํ์ง ์๋๋ก ๋ณ๊ฒฝํ๋ค.
Add `React.useActionState` by rickhanlonii · Pull Request #28491 · facebook/react
Overview Depends on #28514 This PR adds a new React hook called useActionState to replace and improve the ReactDOM useFormState hook. Motivation This hook intends to fix some of the confusion and l...
github.com
React Dom: <form> Actions
Action์ React-DOM์ ์ํ React 19์ ์๋ก์ด <form> ๊ธฐ๋ฅ๊ณผ๋ ํตํฉ๋์ด ์์ต๋๋ค. Action๊ณผ ํจ๊ป ์๋์ผ๋ก ์์์ ์ ์ถํ ์ ์๋๋ก <form>, <input>, <button> ์์์ Action๊ณผ formAction Props๋ก ํต๊ณผ ๊ธฐ๋ฅ ์ง์์ ์ถ๊ฐํ์ต๋๋ค.
<form action={actionFunction}>
<form> Action์ด ์ฑ๊ณตํ๋ฉด React๋ ์ ์ด๋์ง ์๋ ๊ตฌ์ฑ ์์์ ๋ํด ์๋์ผ๋ก ์์์ ์ฌ์ค์ ํฉ๋๋ค. <form>์ ์๋์ผ๋ก ์ฌ์ค์ ํด์ผ ํ๋ ๊ฒฝ์ฐ, ์๋ก์ด requestFormResetReactDOM API๋ฅผ ํธ์ถํ ์ ์์ต๋๋ค.
React DOM: New Hook: useFormStatus
์ค๊ณ ์์คํ ์์๋ ๊ตฌ์ฑ ์์์ ์ถ๊ฐํ์ง ์๊ณ <form>์ ๋ํ ์ ๋ณด์ ์์ธ์คํด์ผ ํ๋ ์ค๊ณ ๊ตฌ์ฑ ์์๋ฅผ ์์ฑํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ ๋๋ค. ์ด ์์ ์ Context๋ฅผ ํตํด ์ํํ ์ ์์ง๋ง, ์ผ๋ฐ์ ์ธ ๊ฒฝ์ฐ๋ฅผ ๋ ์ฝ๊ฒ ๋ง๋ค๊ธฐ ์ํด ๋ค์๊ณผ ๊ฐ์ ์ ํ ์ธ useFormStatus๋ฅผ ์ถ๊ฐํ์ต๋๋ค.
import {useFormStatus} from 'react-dom';
function DesignButton() {
const {pending} = useFormStatus();
return <button type="submit" disabled={pending} />
}
useFormStatus๋ ์์์ด ์ปจํ ์คํธ ๊ณต๊ธ์์ธ ๊ฒ์ฒ๋ผ ๋ถ๋ชจ <form>์ ์ํ๋ฅผ ์ฝ์ต๋๋ค.
New Hook: useOptimistic
๋ฐ์ดํฐ ๋ณํ์ ์ํํ ๋ ๋ ๋ค๋ฅธ ์ผ๋ฐ์ ์ธ UI ํจํด์ ๋น๋๊ธฐ ์์ฒญ์ด ์งํ๋๋ ๋์ ์ต์ข ์ํ๋ฅผ ๋๊ด์ ์ผ๋ก ๋ณด์ฌ์ฃผ๋ ๊ฒ. React 19 ์์๋ ์ด๋ฅผ ์ฝ๊ฒ ํ๊ธฐ ์ํด useOptimistic ๋ผ๋ ์๋ก์ด Hook์ ์ถ๊ฐํ๊ณ ์์ต๋๋ค.
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>
);
}
updateName ์์ฒญ์ด ์งํ๋๋ ๋์ useOptimistic Hook์ ์ฌ์ฉํ๋ฉด OptimisticName์ด ์ฆ์ ๋ ๋๋ง๋ฉ๋๋ค. ์ ๋ฐ์ดํธ๊ฐ ์๋ฃ๋๊ฑฐ๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ฉด React๋ ์๋์ผ๋ก CurrentName ๊ฐ์ผ๋ก ๋ค์ ์ ํ๋ฉ๋๋ค.
New API: Use
Render๋ก ๋ฆฌ์์ค๋ฅผ ์ฝ์ ์ ์๋ ์๋ก์ด API์ธ use.
์๋ฅผ ๋ค์ด, use์ ์ฝ์์ ์ฝ์ ์ ์์ผ๋ฉฐ, ์ฝ์์ด ํด๊ฒฐ๋ ๋๊น์ง ๋ฐ์์ด ์ผ์ ์ค๋จ๋ฉ๋๋ค.
import {use} from 'react';
function Comments({commentsPromise}) {
// `use` will suspend 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.
return (
<Suspense fallback={<div>Loading...</div>}>
<Comments commentsPromise={commentsPromise} />
</Suspense>
)
}
use๋ ๋ ๋๋ก ์์ฑ๋ ์ฝ์์ ์ง์ํ์ง ์์ต๋๋ค.
์ฌ์ฉํ ๋ ๋์์ ๋ง๋ ์ฝ์์ ์ ๋ฌํ๋ ค๊ณ ํ๋ฉด React๋ ๋ค์๊ณผ ๊ฐ์ด ๊ฒฝ๊ณ ํฉ๋๋ค.
์์ ํ๋ ค๋ฉด promises์ ๋ํ ์บ์ฑ์ ์ง์ํ๋ ์์คํ์ค ๊ธฐ๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋๋ ํ๋ ์์ํฌ์์ promise๋ฅผ ์ ๋ฌํด์ผ ํฉ๋๋ค. ํฅํ์๋ ๋ ๋๋ง์์ promises๋ฅผ ๋ ์ฝ๊ฒ ์บ์ํ ์ ์๋๋ก ๊ธฐ๋ฅ์ ์ ๋ฌํ ๊ณํ์ ๋๋ค.
๋ํ ์ปจํ ์คํธ๋ฅผ ์ฌ์ฉํ์ฌ ์ฝ์ ์ ์์ผ๋ฏ๋ก ์กฐ๊ธฐ ๋ฐํ ํ์ ๊ฐ์ ์กฐ๊ฑด๋ถ ์ปจํ ์คํธ๋ฅผ ์ฝ์ ์ ์์ต๋๋ค.
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 ๋ Hook๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ ๋์์๋ง ํธ์ถํ ์ ์์ต๋๋ค. Hook๊ณผ ๋ฌ๋ฆฌ Use๋ ์กฐ๊ฑด๋ถ๋ก ํธ์ถํ ์ ์์ต๋๋ค. ์์ผ๋ก ์ฐ๋ฆฌ๋ ๋ ๋์์ ๋ฆฌ์์ค๋ฅผ ์ฌ์ฉํ์ฌ ์๋นํ๋ ๋ ๋ง์ ๋ฐฉ๋ฒ์ ์ง์ํ ๊ณํ์ ๋๋ค.
React Server Component
(์๋ต)
React 19์ ๊ฐ์ ์ฌํญ
Ref as a Prop
Ref๋ฅผ Function Component์ prop ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.
function MyInput({placeholder, ref}) {
return <input placeholder={placeholder} ref={ref} />
}
//...
<MyInput ref={ref} />
์๋ก์ด ๊ธฐ๋ฅ ๊ตฌ์ฑ ์์๋ ๋ ์ด์ forwardRef๊ฐ ํ์ํ์ง ์์ผ๋ฉฐ, ์๋ก์ด ์ฐธ์กฐ prop์ ์ฌ์ฉํ๊ธฐ ์ํด ๊ตฌ์ฑ ์์๋ฅผ ์๋์ผ๋ก ์ ๋ฐ์ดํธํ๋ ์ฝ๋ ๋ชจ๋๋ฅผ ๊ฒ์ํ ๊ฒ ์ ๋๋ค. ํฅํ ๋ฒ์ ์์๋ forwardRef๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ์ ๊ฑฐํ ๊ฒ ์ ๋๋ค.
ํด๋์ค์ ์ ๋ฌ๋ refs๋ ๊ตฌ์ฑ ์์ ์ธ์คํด์ค๋ฅผ ์ฐธ์กฐํ๋ฏ๋ก prop์ผ๋ก ์ ๋ฌ๋์ง ์์ต๋๋ค.
<Context> as a provider
React 19 ์์๋ <Context.Provider> ๋์ <Context>๋ฅผ ๊ณต๊ธ์๋ก ๋ ๋๋ง ํ ์ ์์ต๋๋ค.
const ThemeContext = createContext('');
function App({children}) {
return (
<ThemeContext value="dark">
{children}
</ThemeContext>
);
}
์ Context ์ ๊ณต์๋ <Context>๋ฅผ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ๊ธฐ์กด ์ ๊ณต์๋ฅผ ๋ณํํ๋ ์ฝ๋ ๋ชจ๋๋ฅผ ๊ฒ์ํ ์์ ์ ๋๋ค. ํฅํ ๋ฒ์ ์์๋ <Context.Provider>๋ฅผ ์ฌ์ฉํ์ง ์์ต๋๋ค.
Cleanup functions for refs
์ด์ ref callback ์์ ์ ๋ฆฌ ๊ธฐ๋ฅ์ ๋ฐํํ ์ ์์ต๋๋ค.
<input
ref={(ref) => {
// ref created
// NEW: return a cleanup function to reset
// the ref when element is removed from DOM.
return () => {
// ref cleanup
};
}}
/>
๊ตฌ์ฑ ์์๊ฐ ๋ง์ดํธ ํด์ ๋๋ฉด React๋ Ref ์ฝ๋ฐฑ์์ ๋ฐํ๋๋ ์ ๋ฆฌ ํจ์๋ฅผ ํธ์ถํ๋ค. ์ด๋ DOM Ref, class, Component Ref, useImperativeHandle์ ๋ํด ์๋ํฉ๋๋ค.
์ด์ ์ React๋ ๊ตฌ์ฑ ์์๋ฅผ ๋ง์ดํธ ํด์ ํ ๋ null๋ก Ref ํจ์๋ฅผ ํธ์ถํ์ต๋๋ค. Ref๊ฐ CleanUp ํจ์๋ฅผ ๋ฐํํ๋ฉด React๋ ์ด์ ์ด ๋จ๊ณ๋ฅผ ๊ฑด๋๋๋๋ค.
ํฅํ ๋ฒ์ ์์๋ ๊ตฌ์ฑ ์์๋ฅผ ๋ง์ดํธ ํด์ ํ ๋ null๋ก ์ฐธ์กฐ๋ฅผ ํธ์ถํ๋ ๊ฒ์ ๊ธ์งํฉ๋๋ค.
useDefferedValue initial value
useDefferedValue์ Initial Value ์ต์ ์ ์ถ๊ฐํ์ต๋๋ค.
(useDefferedValue ๋ ๊ฐ์ ์ ๋ฐ์ดํธ ์ฐ์ ์์๋ฅผ ์ง์ ํ๋ Hook)
function Search({deferredValue}) {
// On initial render the value is ''.
// Then a re-render is scheduled with the deferredValue.
const value = useDeferredValue(deferredValue, '');
return (
<Results query={value} />
);
}
initialValue๊ฐ ์ ๊ณต๋๋ฉด useDefferredValue ๋ ๊ตฌ์ฑ ์์์ ์ด๊ธฐ ๋ ๋์ ๋ํ ๊ฐ์ผ๋ก ๋ฐํํ๊ณ deferrefValue re-render๋ก ๋ฐฑ๊ทธ๋ผ์ด๋์์ re-render์ ์์ฝํฉ๋๋ค.
useDeferredValue – React
The library for web and native user interfaces
react.dev
Support for Document Metadata
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>
);
}
๋ฆฌ์กํธ๊ฐ ์ด ๊ตฌ์ฑ ์์๋ฅผ ๋ ๋๋งํ๋ฉด <title>, <link>, <meta> ํ๊ทธ๊ฐ ํ์๋๊ณ ์๋์ผ๋ก ๋ฌธ์์ <head> ์น์ ์ผ๋ก ํธ์ด์คํธ๋ฉ๋๋ค. ์ด๋ฌํ ๋ฉํ๋ฐ์ดํฐ ํ๊ทธ๋ฅผ ๊ธฐ๋ณธ์ ์ผ๋ก ์ง์ํจ์ผ๋ก์จ ํด๋ผ๋ฆฌ์ธํธ ์ ์ฉ ์ฑ, ์คํธ๋ฆฌ๋ฐ SSR ๋ฐ ์๋ฒ ๊ตฌ์ฑ ์์์ ํจ๊ป ์๋ํ ์ ์๋๋ก ํ ์ ์์ต๋๋ค.
Support for StyleSheets
์คํ์ผ์ํธ๋ ์ธ๋ถ๋งํฌ(<link rel='stylesheet' href="....">)์ ์ธ๋ผ์ธ(<style>...</style>) ๋ชจ๋ ์คํ์ผ ์ฐ์ ์์ ๊ท์น์ผ๋ก ์ธํด DOM์์ ์ ์คํ ์์น ์ง์ ์ด ํ์ํฉ๋๋ค. ๊ตฌ์ฑ ์์ ๋ด์์ ํฉ์ฑ์ ํ์ฉํ๋ ์คํ์ผ์ํธ ๊ธฐ๋ฅ์ ๊ตฌ์ถํ๋ ๊ฒ์ ์ด๋ ต๊ธฐ ๋๋ฌธ์ ์ฌ์ฉ์๋ ์ข ์ข ์์ ์๊ฒ ์์กดํ ์ ์๋ ๊ตฌ์ฑ ์์์์ ๋ฉ๋ฆฌ ๋จ์ด์ง ๋ชจ๋ ์คํ์ผ์ ๋ก๋ํ๊ฑฐ๋ ์ด ๋ณต์ก์ฑ์ ์บก์ํํ๋ ์คํ์ผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
React 19์์๋ ์ด๋ฌํ ๋ณต์ก์ฑ์ ํด๊ฒฐํ๊ณ ์คํ์ผ์ํธ๋ฅผ ์ง์ํ๋ ๋ด์ฅ๋ ํด๋ผ์ด์ธํธ์ ๋์ ๋ ๋๋ง๊ณผ ์๋ฒ์ ์คํธ๋ฆฌ๋ฐ ๋ ๋๋ง์ ๋์ฑ ๊น์ด ์๋ ํตํฉ์ ์ ๊ณตํ๊ณ ์์ต๋๋ค. React 19์ ์คํ์ผ์ํธ์ ์ฐ์ ์์๋ฅผ ์๋ ค์ฃผ๋ฉด 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" /> <-- will be inserted between foo & bar
</div>
)
}
์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง ์ค์ React๋ ์คํ์ผ ์ํธ๋ฅผ <head>์ ํฌํจ์์ผ ๋ธ๋ผ์ฐ์ ๊ฐ ๋ก๋๋ ๋๊น์ง ๊ทธ๋ฆผ์ ๊ทธ๋ฆฌ์ง ์๋๋ก ํฉ๋๋ค. ์ด๋ฏธ ์คํธ๋ฆฌ๋ฐ์ ์์ํ ํ ์คํ์ผ ์ํธ๊ฐ ๋ฆ๊ฒ ๋ฐ๊ฒฌ๋๋ฉด React๋ ์คํ์ผ ์ํธ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋ ์์คํ์ค ๊ฒฝ๊ณ์ ๋ด์ฉ์ ๋๋ฌ๋ด๊ธฐ ์ ์ ์คํ์ผ์ํธ๊ฐ ํด๋ผ์ด์ธํธ์ <head>์ ์ฝ์ ๋๋๋ก ํฉ๋๋ค.
ํด๋ผ์ด์ธํธ ์ธก ๋ ๋๋ง ์ค์ React๋ ๋ ๋๋ง์ ์ปค๋ฐํ๊ธฐ ์ ์ ์๋ก ๋ ๋๋ง ๋ ์คํ์ผ์ํธ๊ฐ ๋ก๋๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฝ๋๋ค. ์์ฉ ํ๋ก๊ทธ๋จ ๋ด์ ์ฌ๋ฌ ์ฅ์์์ ์ด ๊ตฌ์ฑ ์์๋ฅผ ๋ ๋๋งํ๋ ๊ฒฝ์ฐ React๋ ์คํ์ผ์ํธ๋ฅผ ๋ฌธ์์ ํ ๋ฒ๋ง ํฌํจํฉ๋๋ค.
function App() {
return <>
<ComponentOne />
...
<ComponentOne /> // won't lead to a duplicate stylesheet link in the DOM
</>
}
Support for Async scripts
HTML ์ผ๋ฐ ์คํฌ๋ฆฝํธ(<script src="...">)์ ์ง์ฐ ์คํฌ๋ฆฝํธ(<script depar="" src="...">)๋ ๋ฌธ์ ์์๋ก ๋ก๋๋๋ฏ๋ก ๊ตฌ์ฑ ์์ ํธ๋ฆฌ์ ๊น์ ๊ณณ์ ์ด๋ฌํ ์ข ๋ฅ์ ์คํฌ๋ฆฝํธ๋ฅผ ๋ ๋๋งํ๊ธฐ๊ฐ ์ด๋ ต์ต๋๋ค. ๊ทธ๋ฌ๋ ๋น๋๊ธฐ ์คํฌ๋ฆฝํธ(<script async="" src="...">)๋ ์์์ ์์๋ก ๋ก๋๋ฉ๋๋ค.
React 19์์๋ ์คํฌ๋ฆฝํธ ์ธ์คํด์ค๋ฅผ ์ฌ๋ฐฐ์น ๋ฐ ์ค๋ณต ์ ๊ฑฐํ๋ ์์ ์์ด ๊ตฌ์ฑ ์์ ํธ๋ฆฌ ๋ด์ ์ค์ ์คํฌ๋ฆฝํธ์ ์์กดํ๋ ๊ตฌ์ฑ ์์ ๋ด๋ถ ์ด๋์์๋ ๋ ๋๋งํ ์ ์๋๋ก ํจ์ผ๋ก์จ ๋น๋๊ธฐ ์คํฌ๋ฆฝํธ๋ฅผ ๋ ์ ์ง์ํ ์ ์๋๋ก ํ์ต๋๋ค.
function MyComponent() {
return (
<div>
<script async={true} src="..." />
Hello World
</div>
)
}
function App() {
<html>
<body>
<MyComponent>
...
<MyComponent> // won't lead to duplicate script in the DOM
</body>
</html>
}
Support for preloading resources
์ด๊ธฐ ๋ฌธ์ ๋ก๋ ๋ฐ ํด๋ผ์ด์ธํธ ์ธก ์ ๋ฐ์ดํธ ์ค์ ๋ธ๋ผ์ฐ์ ์ ๊ฐ๋ฅํ ํ ๋นจ๋ฆฌ ๋ก๋ํด์ผ ํ ๋ฆฌ์์ค์ ๋ํด ์๋ ค์ฃผ๋ฉด ํ์ด์ง ์ฑ๋ฅ์ ๊ทน์ ์ธ ์ํฅ์ ๋ฏธ์น ์ ์์ต๋๋ค.
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>
Support for Custom Elements
React 19๋ Custom Elements์ ๋ํ ์์ ํ ์ง์์ ์ถ๊ฐํ๊ณ Custom Elements Everywhere์ ๋ํ ๋ชจ๋ ํ ์คํธ๋ฅผ ํต๊ณผํฉ๋๋ค.
์ด์ ๋ฒ์ ์์๋ React๊ฐ ์ธ์๋์ง ์๋ Props๋ฅผ ์์ฑ์ด ์๋ ์์ฑ์ผ๋ก ์ฒ๋ฆฌํ๊ธฐ ๋๋ฌธ์ React์์ Custom Elements๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ด๋ ค์ ์ต๋๋ค. React 19์์๋ ํด๋ผ์ด์ธํธ ๋ฐ SSR ์ค์ ์๋ํ๋ ์์ฑ์ ๋ํ ์ง์์ ๋ค์๊ณผ ๊ฐ์ ์ ๋ต์ผ๋ก ์ถ๊ฐํ์ต๋๋ค.
Server Side Rendering: ์ฌ์ฉ์ ์ง์ ์์์ ์ ๋ฌ๋ props๋ ํด๋น ์ ํ์ด ๋ฌธ์์ด, ์ซ์ ๋๋ ๊ฐ์ด true์ ๊ฐ์ ๊ธฐ๋ณธ ๊ฐ์ด๋ฉด ์์ฑ์ผ๋ก ๋ ๋๋ง๋ฉ๋๋ค. ๊ฐ์ฒด, ๊ธฐํธ, ํจ์ ๋๋ ๊ฐ false์ ๊ฐ์ primitive๊ฐ ์๋ ์ ํ์ props๋ ์๋ต๋ฉ๋๋ค.
Client Side Rendering: Custom Element ์ธ์คํด์ค์ ์์ฑ๊ณผ ์ผ์นํ๋ props๋ properties๋ก ํ ๋น๋๊ณ ๊ทธ๋ ์ง ์์ผ๋ฉด attributes๋ก ํ ๋น๋ฉ๋๋ค.