useFormState הוא Hook שמאפשר לעדכן state על בסיס תוצאת פעולה של טופס.
const [state, formAction] = useFormState(fn, initialState, permalink?);Reference
useFormState(action, initialState, permalink?)
קראו ל-useFormState ברמה העליונה של הקומפוננטה כדי ליצור state לקומפוננטה שמתעדכן כשפעולת טופס מופעלת. אתם מעבירים ל-useFormState פונקציית form action קיימת יחד עם state התחלתי, והפונקציה מחזירה action חדשה שתשתמשו בה בטופס, יחד עם מצב הטופס העדכני ביותר. מצב הטופס העדכני גם מועבר לפונקציה שסיפקתם.
import { useFormState } from "react-dom";
async function increment(previousState, formData) {
return previousState + 1;
}
function StatefulForm({}) {
const [state, formAction] = useFormState(increment, 0);
return (
<form>
{state}
<button formAction={formAction}>Increment</button>
</form>
)
}מצב הטופס הוא הערך שמוחזר מה-action כשהטופס הוגש לאחרונה. אם הטופס עדיין לא הוגש, זה יהיה ה-state ההתחלתי שהעברתם.
בשימוש עם Server Action, useFormState מאפשר להציג את תגובת השרת מהגשת הטופס עוד לפני שה-hydration הושלם.
Parameters
fn: הפונקציה שתיקרא כששולחים את הטופס או לוחצים על כפתור. כשהפונקציה נקראת, היא תקבל את מצב הטופס הקודם (בהתחלה ה-initialStateשהעברתם, ובהמשך ערך ההחזרה הקודם שלה) כארגומנט ראשון, ואז את הארגומנטים ש-form action מקבלת בדרך כלל.initialState: הערך שתרצו שיהיה למצב בתחילה. הוא יכול להיות כל ערך שניתן לסריאליזציה. מתעלמים מהארגומנט הזה אחרי הפעלת הפעולה בפעם הראשונה.- אופציונלי
permalink: מחרוזת שמכילה את URL העמוד הייחודי שהטופס הזה משנה. מיועד לעמודים עם תוכן דינמי (למשל feed) יחד עם progressive enhancement: אםfnהיא server action והטופס נשלח לפני ש-JavaScript bundle נטען, הדפדפן ינווט ל-URL של ה-permalink שצוין במקום ל-URL של העמוד הנוכחי. ודאו שאותה קומפוננטת טופס מרונדרת בעמוד היעד (כולל אותה actionfnואותוpermalink) כדי ש-React תדע להעביר את המצב. אחרי שהטופס עובר hydration, לפרמטר הזה אין השפעה.
Returns
useFormState מחזירה מערך עם שני ערכים בדיוק:
- המצב הנוכחי. בזמן הרינדור הראשון הוא יתאים ל-
initialStateשהעברתם. אחרי שהפעולה מופעלת, הוא יתאים לערך שהוחזר מהפעולה. - פעולה חדשה שאפשר להעביר כ-prop בשם
actionלקומפוננטתformשלכם, או כ-prop בשםformActionלכל קומפוננטתbuttonבתוך הטופס.
Caveats
- כשמשתמשים במסגרת שתומכת ב-React Server Components,
useFormStateמאפשרת להפוך טפסים לאינטראקטיביים עוד לפני ש-JavaScript בוצע בלקוח. בשימוש בלי Server Components, זה שקול ל-state מקומי של קומפוננטה. - הפונקציה שמועברת ל-
useFormStateמקבלת ארגומנט נוסף — ה-state הקודם או ההתחלתי — כארגומנט ראשון. לכן ה-signature שלה שונה מאשר שימוש ישיר בה כ-form action בליuseFormState.
Usage
שימוש במידע שמוחזר מפעולת טופס
קראו ל-useFormState ברמה העליונה של הקומפוננטה כדי לגשת לערך ההחזרה של action מהפעם האחרונה שהטופס הוגש.
import { useFormState } from 'react-dom';
import { action } from './actions.js';
function MyComponent() {
const [state, formAction] = useFormState(action, null);
// ...
return (
<form action={formAction}>
{/* ... */}
</form>
);
}useFormState מחזירה מערך עם שני פריטים בדיוק:
- ה-state הנוכחי של הטופס, שמוגדר בתחילה ל-state ההתחלתי שסיפקתם, ואחרי הגשת הטופס מוגדר לערך ההחזרה של ה-action שסיפקתם.
- action חדשה שאתם מעבירים ל-
<form>כ-prop בשםaction.
כשהטופס נשלח, פונקציית ה-action שסיפקתם תיקרא. ערך ההחזרה שלה יהפוך ל-state הנוכחי החדש של הטופס.
ה-action שסיפקתם תקבל גם ארגומנט ראשון חדש: ה-state הנוכחי של הטופס. בפעם הראשונה שהטופס נשלח, זה יהיה ה-state ההתחלתי שסיפקתם; בשליחות הבאות, זה יהיה ערך ההחזרה מהפעם הקודמת שהפעולה נקראה. שאר הארגומנטים זהים למצב שבו useFormState לא הייתה בשימוש.
function action(currentState, formData) {
// ...
return 'next state';
}Example 1 of 2: הצגת שגיאות טופס
כדי להציג הודעות כמו שגיאה או toast שמוחזרות מ-Server Action, עטפו את הפעולה בקריאה ל-useFormState.
import { useState } from "react"; import { useFormState } from "react-dom"; import { addToCart } from "./actions.js"; function AddToCartForm({itemID, itemTitle}) { const [message, formAction] = useFormState(addToCart, null); return ( <form action={formAction}> <h2>{itemTitle}</h2> <input type="hidden" name="itemID" value={itemID} /> <button type="submit">Add to Cart</button> {message} </form> ); } export default function App() { return ( <> <AddToCartForm itemID="1" itemTitle="JavaScript: The Definitive Guide" /> <AddToCartForm itemID="2" itemTitle="JavaScript: The Good Parts" /> </> ) }
Troubleshooting
הפעולה שלי כבר לא יכולה לקרוא את נתוני הטופס שנשלחו
כשעוטפים פעולה עם useFormState, היא מקבלת ארגומנט נוסף כארגומנט ראשון. לכן נתוני הטופס שנשלחו הופכים ל-ארגומנט השני במקום הראשון כפי שבדרך כלל. הארגומנט הראשון החדש שנוסף הוא מצב הטופס הנוכחי.
function action(currentState, formData) {
// ...
}