• בלוג
  • עמוד 38
  • הצצה לעתיד: פעולות צד שרת בריאקט ו Next.js 14

הצצה לעתיד: פעולות צד שרת בריאקט ו Next.js 14

30/10/2023

לפני כמה ימים כתבתי כאן על פעולות צד-לקוח, פיצ'ר חמוד של ריאקט שהולך לחסוך לנו כמה הקלקות בכתיבת קוד שמטפל בטפסים. החלק השני שלו, שנקרא Server Actions, כבר הרבה יותר מהפכני ודורש תמיכה מפריימוורק בצד שרת. בזכות Next.JS 14 שיצא עכשיו נוכל לראות איך זה עובד ולהבין את הכיוון של ריאקט בתור Full Stack Framework.

1. הסיפור מאחורי

פעולות צד-שרת הן מנגנון שבו קומפוננטה ריאקטית מגישה טופס לשרת, וכל תהליך הגשת הטופס וקבלת התשובה מנוהל על ידי הפריימוורק. בכתיבת פעולות צד שרת אנחנו צריכים לכתוב רק שני דברים:

  1. את קוד הקומפוננטה, כולל שימוש ב Hook מיוחד כדי להציג ממשק שונה למצב טעינה.

  2. את הפונקציה בשרת (ב node.js) שמטפלת בהגשת הטופס.

כל הנושא של שליחת הודעה ב http, סריאליזציה של הפרמטרים, המתנה ופיענוח תשובות מבוצע בצורה אוטומטית על ידי הפריימוורק.

2. דוגמת קוד

קוד? ברור. בפרויקט next.js אנחנו צריכים בסך הכל שני קבצים. הקובץ page.tsx עם הקומפוננטה של העמוד והקובץ server_actions.ts שמגדיר את הקוד שמטפל בטופס בצד השרת.

בקובץ server_actions.ts אני כותב:

'use server'
const process = require('node:process');

export async function createItem(data: FormData) {
  console.log(`Client sent form: ${JSON.stringify(Object.fromEntries(data))}`);
  console.log(`I'm a server action pid = ${process.pid}`);
  await new Promise((resolve, reject) => {
    setTimeout(resolve, 3000)
  });
  return `${process.pid}/${data.get('name')}`
}

התחילית 'use server' אומרת ל next.js שאת הפונקציה הזאת צריך להריץ בצד שרת. הפונקציה עצמה משתמשת בדברים של צד שרת לדוגמה process.pid, ומקבלת בתור קלט משהו מסוג FormData - אלה הערכים בטופס שיגיעו מהלקוח.

בקובץ page.tsx יהיה לי קוד קצת יותר ארוך שמגדיר שתי קומפוננטות. הקומפוננטה הראשונה היא הטופס:

export default function Page() {
  const [id, setId] = useState('');

  async function onSubmit(formData: FormData) {
    const nextId = await createItem(formData);
    setId(nextId);
  }
  return (
    <form action={onSubmit}>
      <Header />
      {id != '' && <p>Ready. Id = {id}</p>}
      <input type="text" name="name" />
      <button type="submit">Submit</button>
    </form>
  );
}

אני מגדיר action לטופס ובתוך הפונקציה פשוט מפעיל את הפונקציה מ server_actions.ts ושומר את התשובה למשתנה. מאחורי הקלעים ריאקט ישלח את הטופס לשרת, הפונקציה תרוץ בשרת ותחזיר את התוצאה בתשובה לבקשה, הכל דרך הרשת ועם סריאליזציה אוטומטית.

בשביל להציג מסך טעינה כשהמידע נשלח לשרת בניתי את הקומפוננטה Header עם הקוד הבא:

function Header() {
  const status = useFormStatus()

  if (status.pending) {
    return <p>Loading...</p>
  }
}

הפונקציה useFormStatus הגיעה מ react-dom (רק בגירסאות חדשות של ריאקט), ומחזירה אוביקט עם מספר שדות שמספר מה מצב הגשת הטופס האחרון שהוגש.

שורה תחתונה מנגנון Server Actions הופך את ריאקט להרבה יותר פריימוורק מלא לפיתוח Full Stack מאשר ספריה קטנה וגמישה לפיתוח שכבת התצוגה. יהיה מעניין לראות את ההשלכות של זה על האקוסיסטם. מצד אחד אין ספק שהרבה יותר קל לבנות פרויקט Full Stack מאפס כשכל הכלים מנגנים יפה יחד, אבל מצד שני הרבה אנשים (כולל אני) יתגעגעו לגמישות המינימליסטית של ריאקט הישן והטוב. נמשיך לעקוב.