ð React 19 | æ°ããã¯ïŒãã©ãŒã 管çã®é²å ð¡ éçºå¹çUPã®ææ°æ©èœãŸãšã
以äžã§ã¯ãReact19ã®èæ¯ãææ°æ©èœããã£ãšæŽçããªãããèªåã®åå¿é²ãšããŠããŸãšããŠã¿ãŸããã
ã¯ããã«ïŒ é²åãããŠã§ãéçºã®ããŒãº ð
ããæ°å¹ŽãWebã¢ããªéçºã¯ä»¥äžã®ãããªãã€ã³ãã匷ãæèããŠäœãã±ãŒã¹ãå¢ããŠããããã«æããŸãã
- ååããŒãã®éãïŒ ååããŒãããç»é¢ã«ã³ã³ãã³ãã衚瀺ããããŸã§ã®æéãããã«çãã§ãããããŠãŒã¶ãŒããåŸ ã¡ç²ããããªãããã«ãã工倫ãéèŠã
- ã€ã³ã¿ã©ã¯ãã£ãæ§ïŒ ã¢ããªã®èŠæš¡ã倧ãããªãã»ã©ãç¶æ 管çããªã¢ã«ã¿ã€ã æŽæ°ãè€éã«ãªããã¡ããµã¯ãµã¯åãUIãšã¹ãã¬ã¹ã®ãªãæäœæãå®çŸããã®ããã€ã³ãã
- SEO察å¿ïŒ SPAã§ãæ€çŽ¢ãšã³ãžã³ã«ãã£ããã€ã³ããã¯ã¹ãããããã«ãSSRãSSGã®å°å ¥ãäžè¬çã«ãªãã€ã€ããã
- ãããã¯ãŒã¯ããããããªãç°å¢ãžã®å¯Ÿå¿ïŒ ãªãã©ã€ã³ãäœéåç·ã§ãããŠãŒã¶ãŒãé床ã«åŸ ãããªãããã®ãã£ãã·ã¥ãããŒãåå²ãªã©ã®å·¥å€«ãéèŠã«ã
ãããã£ãèŠä»¶ããã¹ãŠæºããã«ã¯ãSSR/SSG/ISR ãšãã£ãã¬ã³ããªã³ã°ææ³ããç¶æ 管çãããã©ãŒãã³ã¹æé©åãªã©ãå¹ åºãç¥èãå¿ èŠã§ãã
ãã®äžã§ãReactããããŸã§ã©ã®ããã«é²åããŠããã®ã ð
Reactã¯äžèšã®ããŒãºã«å¿ãã圢ã§ãå°ããã€é²åããŠããŸããã
- React16.8ïŒ ãããŸã§ã¯ã©ã¹ã³ã³ããŒãã³ãäžå¿ã ã£ãç¶æ 管çãã©ã€ããµã€ã¯ã«ã¡ãœããã«ããå¯äœçšåŠçã«ä»£ããææ³ãšããŠãHooksïŒäž»ã« useStateã»useEffect ãªã©ïŒãææ¡ããã颿°ã³ã³ããŒãã³ãã ãã§ç¶æ ãå¯äœçšãã·ã³ãã«ã«æ±ããããã«ãªããããžãã¯ã®åå©çšæ§ãé£èºçã«åäžããŸããã
- React18ïŒ è€æ°ã®ã¬ã³ããªã³ã°ã¿ã¹ã¯ãå¹ççã«ã¹ã±ãžã¥ãŒãªã³ã°ã§ããåæã¬ã³ããªã³ã°ïŒConcurrent RenderingïŒããè€æ°ã®stateæŽæ°ããŸãšããŠåŠçããèªåãããåŠçïŒAutomatic BatchingïŒã匷åãããã¢ããªã±ãŒã·ã§ã³å šäœã®æç»ãããã¹ã ãŒãºãã€å¹ççãªä»çµã¿ã«ã
- RSCïŒReact Server ComponentsïŒã®ç»å ŽãšReact19ïŒ ãµãŒããŒåŽã§ã³ã³ããŒãã³ããåŠçããŠã¯ã©ã€ã¢ã³ããžã¯æå°éã®ããŒã¿ã ããéãRSCïŒReact Server ComponentsïŒãšããæ°ããªã¢ãŒããã¯ãã£ãç»å Žãå ããŠãReact19ã§ã¯ãåŸè¿°ãããã©ãŒã ç®¡çæ©èœã®ãããªã匷åããµãŒããŒãµã€ãé¢é£ã®æ¡åŒµãé²ããããŠããŸãã
React19ã®æ³šç®æ©èœ ð¡
ä»åã®React19ã§ã¯ããããŸã§ã®é²åã«å ããå€ãã®ã¢ããããŒãã宿œãããŸããããã®äžãããããã€ã泚ç®ãã¹ããã€ã³ããããã¯ã¢ããããŸãã
ãã©ãŒã 管çãã·ã³ãã«å
React 19ã§ã¯ããã©ãŒã 管çãããã«æ±ãããããªããŸããã
-
<form action={éåæé¢æ°}>ã«ãããã©ãŒã åŠçã®ç°¡çŽ å
actionã«ãã©ãŒã éä¿¡æã®éåæé¢æ°ãçŽæ¥çã«åŒã³åºããããã«ãªããFormDataãªããžã§ã¯ããèªåã§åãåããããã«ãªã£ãããšã§ããã©ãŒã éä¿¡ã®å®è£ ãããã·ã³ãã«ã«èšè¿°å¯èœã«ãªããŸããã -
useFormStatusããã¯
ãã©ãŒã ã®éä¿¡äžïŒpendingïŒç¶æ ãåå«ã³ã³ããŒãã³ãããç°¡åã«ååŸã§ããããããã¿ã³ã®disabledå¶åŸ¡ãªã©ã楜ã«è¡ããŸããUIã®äžè²«ããç¶æ 管çã«ã圹ç«ã€äŸ¿å©ãªããã¯ã§ãã
useTransitionã®ã¢ã¯ã·ã§ã³å¯Ÿå¿
useTransitionã®startTransitionã«æž¡ãã³ãŒã«ããã¯ãasync颿°ãšããŠå®çŸ©ã§ããããã«ãªããŸãããããã«ããã以äžã®ã¡ãªããããããŸãã
ã»éåæåŠçãã¹ã ãŒãºã«ãã©ã³ãžã·ã§ã³åããŠæ±ãã
ã»åŠçéå§æã«isPending=trueãå®äºåŸã«falseãžèªåçã«åãæ¿ããããããã³ãã£ã³ã°ç¶æ
ãæåã§ç®¡çããæéã倧å¹
ã«æžå°
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>
);
}
æ°ããã¯: useActionState / useFormStatus / useOptimistic
-
useActionState
ã»éåæã¢ã¯ã·ã§ã³ïŒãã©ãŒã éä¿¡å«ãïŒã®çµæããšã©ãŒããããŠãã³ãã£ã³ã°ç¶æ ããŸãšããŠç®¡çã
ã»Canaryçã§useFormStateãšåŒã°ããŠãããã®ãæçµçã«useActionStateã«åç§°å€æŽã
ã»<form action={submitAction}> ã«æž¡ããéãéä¿¡å®äºããšã©ãŒãããŒã«ããã¯ãªã©ãäžæ¬ã§ç®¡çã§ããã -
useFormStatus
ã»<form> èŠçŽ ã®ãã³ãã£ã³ã°ç¶æ ãåå«ã³ã³ããŒãã³ãããåç §å¯èœã
ã»ãéä¿¡äžãã©ãããã ããååŸãããå Žåã«ç¹åãUIéšåããã¶ã€ã³ã³ã³ããŒãã³ãã§ã®ãã¿ã³å¶åŸ¡ãªã©ã«äŸ¿å©ã -
useOptimistic
ã»æ¥œèгçUIãæè»œã«å®è£ ã§ããããã¯ããŠãŒã¶ãŒæäœãå³åº§ã«UIåæ ãã倱ææã«å ã®ç¶æ ãžããŒã«ããã¯ããåŠçãã·ã³ãã«ã«æžããã
useããã¯ã§éåæããŒã¿ååŸãããã¹ãããª
useã䜿ããš Promiseãåãåã£ãŠèªåãµã¹ãã³ãããŠãããã®ã§ãããŒã¿ãæããŸã§ <Suspense> ãæŽ»çšããŠããŒãã£ã³ã°è¡šç€ºãåºãããšãç°¡åã«ãªããŸãã
import { Suspense, use } from 'react';
function Comments({ commentsPromise }) {
const comments = use(commentsPromise);
return comments.map(c => <p key={c.id}>{c.text}</p>);
}
function App({ commentsPromise }) {
return (
<Suspense fallback={<p>Loading...</p>}>
<Comments commentsPromise={commentsPromise} />
</Suspense>
);
}
React19ã®ã³ãŒããµã³ãã«é ð
å®éã«React19ã®æ°æ©èœïŒäž»ã«æ°ããã¯ïŒã䜿ããšã©ã®ãããªæãã«ãªãã®ããããã€ãã³ãŒãäŸãèšèŒããŸãã
1. <form action={éåæé¢æ°}> ã§ãã©ãŒã éä¿¡ãã·ã³ãã«ã«
async function handleSubmit(formData) {
const newUser = {
username: formData.get("username"),
email: formData.get("email"),
};
try {
const response = await fetch("https://api.example.com/users", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(newUser),
});
console.log("[Action] User successfully submitted:", newUser);
} catch (error) {
console.error("[Action] Failed to submit user:", error);
}
}
function Action() {
return (
<>
<h3>Action Example</h3>
<form action={handleSubmit}>
<div>
<label>User Name</label>
<input type="text" name="username" required />
</div>
<div>
<label>Email</label>
<input type="email" name="email" required />
</div>
<button type="submit">Submit</button>
</form>
</>
);
}
export default Action;
ãã€ã³ã:
ã»actionã«ãã©ãŒã éä¿¡æã®éåæé¢æ°ãçŽæ¥åŒã³åºããããã«ãªããFormDataãªããžã§ã¯ããèªåã§åãåããããã«ãªã£ãããšã§ããã©ãŒã éä¿¡ã®å®è£
ãããã·ã³ãã«ã«èšè¿°å¯èœã«ã
ã»useFormStatusãšçµã¿åãããããšã§éä¿¡äžã®ç¶æ
ã管çããããïŒãã¿ã³ã®ç¡å¹åããéä¿¡äžâŠãã®è¡šç€ºãç°¡åã«å®è£
ã§ããïŒã
2. useActionState ã䜿ã£ããã©ãŒã éä¿¡ã®ç®¡ç
import { useActionState } from "react";
async function handleProfileUpdate(prevState, formData) {
const name = formData.get("username");
if (name === "NOA") {
return null;
} else {
return "Error: name must be 'NOA'.";
}
}
function FormState() {
const [message, submitAction, isPending] = useActionState(
handleProfileUpdate,
null
);
return (
<>
<h3>useActionState() example</h3>
<form action={submitAction}>
<label>Name</label>
<input type="text" name="username" />
<button disabled={isPending}>Submit</button>
{message && <p>{message}</p>}
</form>
</>
);
}
export default FormState;
ãã€ã³ã:
ã»useActionStateã¯ãã¢ã¯ã·ã§ã³å®è¡ãçµæã®åãåãïŒãšã©ãŒå«ãïŒããã³ãã£ã³ã°ãäžæ¬ç®¡çããŠãããã
ã»ã¡ãã»ãŒãžããšã©ãŒããŸãšããŠæ±ããã®ã§ããã©ãŒã åšãã®å®è£
ãã¹ãããªã
3. useFormStatus ã§ãã©ãŒã éä¿¡äžã®ç¶æ ãããããæ€ç¥
import { useFormStatus } from "react-dom";
function SubmitButton() {
const { pending } = useFormStatus();
return (
<button disabled={pending}>
{pending ? "Submitting..." : "Submit"}
</button>
);
}
async function fakeAction() {
// 2ç§åŸ
æ©
await new Promise((resolve) => setTimeout(resolve, 2000));
console.log("[useFormStatus] Form submitted!");
}
function FormStatus() {
return (
<>
<h3>useFormStatus() example</h3>
<form action={fakeAction}>
<SubmitButton />
</form>
</>
);
}
export default FormStatus;
ãã€ã³ãïŒ
ã»<form> éä¿¡ãå®äºãããŸã§pendingãèªåã§trueã«ãªããå®äºæã«falseã«æ»ãã
4. useOptimisticã§æ¥œèгçUIãç°¡åå®è£
import { useState, useOptimistic } from "react";
function Optimistic() {
const [messages, setMessages] = useState([
{ text: "Initial message", sending: false },
]);
// 楜芳çUIåæ ã®ããã¯
const [optimisticMsgs, addOptimisticMsg] = useOptimistic(
messages,
(currentMessages, newMessage) => [
...currentMessages,
{ text: newMessage, sending: true },
]
);
async function sendFormData(formData) {
const msgText = formData.get("username");
// æ¬äŒŒçã«1ç§åŸ
ã¡ïŒãµãŒããŒå¿çæ³å®ïŒ
await new Promise((res) => setTimeout(res, 1000));
setMessages((prev) => [...prev, { text: msgText, sending: false }]);
}
async function handleSubmit(formData) {
// å
ã«UIãæŽæ°ãã¡ãã
addOptimisticMsg(formData.get("username"));
// å®éã®éä¿¡
await sendFormData(formData);
}
return (
<>
{optimisticMsgs.map((msg, i) => (
<div key={i} style={{ fontWeight: "bold" }}>
{msg.text}
{msg.sending && <small> (Sending...)</small>}
</div>
))}
<form action={handleSubmit}>
<h3>useOptimistic() example</h3>
<div>
<label>Username</label>
<input type="text" name="username" />
</div>
<button type="submit">Send</button>
</form>
</>
);
}
export default Optimistic;
ãã€ã³ãïŒ
ã»ãŠãŒã¶ãŒæäœâå³åº§ã«UIæŽæ°â倱ææã«ããŒã«ããã¯ããšãããæ¥œèгçUIããããããªã³ãŒãã§å®çŸã
ã»UXåäžã«ç¹ããæ©èœãå
¬åŒããã¯ãšããŠãµããŒãããŠãããããããžãã¯ãæ£ãã°ããä¿å®ããããã
ãŸãšã
React19ã§ã¯ããã©ãŒã 管çãäžå¿ãšããæ°æ©èœïŒActionsãæ°ããã¯ïŒuseActionState,useFormStatus,useOptimistic ãªã©ïŒã远å ãããŸãããããã«ããããã³ãã£ã³ã°ç¶æ ããšã©ãŒåŠçãæ¥œèгçUIã®å®è£ ãå ¬åŒæ©èœãšããŠæ±ãããããåŸæ¥ãããã·ã³ãã«ãã€å¯èªæ§ã®é«ãã³ãŒããæžããŸããããã«useããã¯ãçšããéåæããŒã¿ååŸããReact Server ComponentsïŒRSCïŒã®æ¬æ Œå§åã«ãããéçºè äœéšãšãŠãŒã¶ãŒäœéšã®äž¡é¢ã§å€§ããªé²åãéããŠããŸãããã§ã«React19ã®å®å®çããªãªãŒã¹ãããŠããããã察å¿å¯èœãªéšåããç©æ¥µçã«åãå ¥ããŠããããã§ããïŒ
Discussion