Forms & useOptimistic
useFormStatus: pending โดยไม่ต้อง drilling
หัวข้อที่มีชื่อว่า “useFormStatus: pending โดยไม่ต้อง drilling”บ่อยครั้งคุณอยากให้ submit button รู้ว่า form ของตัวเอง pending อยู่ไหม — เพื่อ disable ตัวเองและแสดง spinner การส่ง isPending ลงไปทุก component ระหว่างทางน่าเบื่อ useFormStatus (จาก react-dom) ให้ component อ่าน status ของ <form> ที่เป็น parent ที่ใกล้ที่สุดได้ตรง ๆ:
import { useFormStatus } from 'react-dom';
// This button reads the enclosing form's status — no props needed.function SubmitButton() { const { pending } = useFormStatus(); return ( <button type="submit" disabled={pending}> {pending ? 'Saving…' : 'Save'} </button> );}
function ProfileForm({ action }) { return ( <form action={action}> <input name="name" /> <SubmitButton /> {/* knows the form is pending, with zero prop drilling */} </form> );}กฎเดียว: useFormStatus อ่าน form ที่เป็น parent ดังนั้น SubmitButton ต้องถูก render อยู่ข้างใน <form> ไม่ใช่เป็น component ที่ render form เอง
useOptimistic: แสดงผลลัพธ์ก่อนที่จะเป็นจริง
หัวข้อที่มีชื่อว่า “useOptimistic: แสดงผลลัพธ์ก่อนที่จะเป็นจริง”เพื่อให้ UX กระฉับกระเฉง คุณมักอยากแสดงผลลัพธ์ที่ คาดว่าจะเกิด ทันทีและแก้ก็ต่อเมื่อ request ล้มเหลว useOptimistic ให้ optimistic value ที่คุณ set ทันทีและ React จะ revert กลับไปเป็นค่าจริงอัตโนมัติเมื่อ action จบ:
import { useOptimistic } from 'react';
function Thread({ messages, sendMessage }) { const [optimisticMessages, addOptimistic] = useOptimistic( messages, (current, newText) => [...current, { text: newText, sending: true }], );
async function formAction(formData) { const text = formData.get('message'); addOptimistic(text); // show it immediately, marked "sending" await sendMessage(text); // real request; React reconciles when it resolves }
return ( <> {optimisticMessages.map((m, i) => ( <p key={i}>{m.text} {m.sending && <small>(sending…)</small>}</p> ))} <form action={formAction}> <input name="message" /> <button type="submit">Send</button> </form> </> );}message ปรากฏทันทีที่คุณ submit เมื่อ sendMessage resolve, React จะ drop entry ที่เป็น optimistic แล้วใช้ state จริงแทน; ถ้า sendMessage ล้มเหลว React จะ revert อัตโนมัติ คุณจึงไม่ต้อง roll back เอง
sequenceDiagram participant U as User participant O as useOptimistic participant S as server action U->>O: submit (addOptimistic) O->>U: show optimistic value instantly O->>S: await real request S-->>O: success then keep real state Note over O,U: on failure React reverts automatically
สอง hook นี้รวมกันทำให้ form รู้สึกทันใจ: useOptimistic สำหรับ feedback ทันที, useFormStatus สำหรับ affordance เรื่อง pending บนปุ่ม — ทั้งคู่โดยไม่ต้องร้อย state ผ่าน props