איך להעלות תמונה (או כל קובץ אחר) ב Next.JS ב 2025
ריאקט 19 ו next 15 עובדים יחד בהרמוניה כדי לאפשר לנו המתכנתים הפשוטים לכתוב אפליקציות Full Stack במהירות. אחד המקומות שקיבל טיפול באינטגרציה הזו הוא הטפסים. בואו נראה איך עובדים עם טפסים ב 2025 ב React ו Next ובפרט איך להעלות תמונות לשרת.
1. קוד הטופס
רעיון ראשון שהחברים בריאקט וב Vercel ממליצים עליו הוא שלא חייבים לשמור את הערכים מהטופס במשתני State. כן אפשר לעשות את זה אם רוצים וולידציה, אבל בגדול אם הוולידציה שלכם קורית רק כשמגישים את הטופס אפשר לחזור לחיים שלפני הסטייט ופשוט לכתוב טופס עם שמות לשדות, ולבדוק את הערכים בפונקציה מרכזית אחת.
קוד הטופס שלי נראה כך:
'use client';
import { useActionState, } from "react"
import { saveImage } from '@/lib/save-image';
export default function Home() {
const [state, formAction, isPending] = useActionState(async (previousState: string, formData: FormData) => {
const file = formData.get('image') as File;
const description = formData.get('description') as string || "Default description";
if (!file || file.size === 0) {
return "No Image Selected"
}
if (!description) {
return "No Description Provided"
}
return await saveImage(file, description);
}, "");
return (
<div>
<p>{state}</p>
<form action={formAction}>
<input type="text" name="description" />
<input type="file" name='image' />
<input type="submit" value="Save Image" />
</form>
</div>
)
}
הפונקציה שאני מעביר ל useActionState
אחראית גם על וולידציה, גם על שליחת המידע לשרת וגם על הגדרת State כתוצאה מתשובת השרת. הפרמטר האחרון לפונקציה הוא הסטייט הראשוני, לפני שהטופס הוגש, והוא יישמר במשתנה החוזר state. אחרי הגשת הטופס הערך החוזר מהפונקציה יוכנס לתוך אותו משתנה state.
מנגנון זה מאפשר לנו להציג הודעה למשתמשים אחרי שהטופס הוגש, או להראות שגיאות מצד שרת או שגיאות וולידציה. בטופס הדוגמה אני משתמש במחרוזת רגילה ופשוט מציג אותה על המסך מעל הטופס. ברינדור הראשון זו תהיה מחרוזת ריקה ואחרי שיוגש הטופס יופיע שם הטקסט שיחזור מצד השרת, או הודעות השגיאה שחוזרות מהפונקציה אם יש שגיאת וולידציה.
2. צד שרת
החלק השני של הקוד הוא הפונקציה saveImage
:
'use server';
import { read } from 'node:fs';
import fs from 'node:fs/promises';
export async function saveImage(
image: File,
description: string,
): Promise<string> {
console.log(`Saving image: ${image.name}`);
const buffer = await image.stream().getReader().read();
const data = buffer.value;
if (!data) return "Missing Image File"
const path = `./images/${image.name}`;
const file = await fs.writeFile(path, data);
return 'Image saved OK';
}
אל תשתמשו בה במערכת אמיתית כי היא לא מנקה את שם הקובץ, אבל כן אפשר להבין מכאן את המבנה:
הפונקציה לוקחת את הקובץ בתור אוביקט File, שזה אוביקט שמשותף גם לצד לקוח וגם לצד שרת.
מתוך ה File אפשר לקחת stream ודרכו להגיע לתוכן.
אם הכל בסדר נכתוב את המידע לקובץ ונחזיר הודעה.