לדלג לתוכן

9.3 קומפוננטות שרת וקליינט תרגול

תרגול - קומפוננטות שרת וקליינט - Server and Client Components

תרגיל 1 - זיהוי סוג הקומפוננטה

לכל אחת מהקומפוננטות הבאות, החליטו אם היא צריכה להיות Server Component או Client Component, והסבירו למה:

  1. קומפוננטה שמציגה רשימת מוצרים מבסיס נתונים
  2. קומפוננטה עם טופס הרשמה (שדות קלט וכפתור שליחה)
  3. קומפוננטה שמציגה שעון בזמן אמת
  4. קומפוננטה שקוראת קובץ JSON מהשרת ומציגה אותו
  5. קומפוננטה עם אקורדיון (פתיחה/סגירה של תוכן)
  6. קומפוננטה שמציגה תוכן Markdown שהומר ל-HTML

ממשו כל אחת מהקומפוננטות (לפחות 4 מתוך 6).


תרגיל 2 - הפרדת שרת וקליינט

בניתם קומפוננטה אחת שעושה הכל. פצלו אותה נכון:

// לפני - קומפוננטה אחת שגויה
"use client";
import { prisma } from "@/lib/prisma";
import { useState } from "react";

export default async function ProductsPage() {
  const products = await prisma.product.findMany();
  const [search, setSearch] = useState("");

  const filtered = products.filter(p =>
    p.name.includes(search)
  );

  return (
    <div>
      <input value={search} onChange={e => setSearch(e.target.value)} />
      <ul>
        {filtered.map(p => <li key={p.id}>{p.name}</li>)}
      </ul>
    </div>
  );
}

פצלו לשתי קומפוננטות:
- Server Component ששולף את הנתונים
- Client Component שמנהל את הסינון והחיפוש


תרגיל 3 - תבנית Provider

צרו מערכת theme (בהיר/כהה) לאפליקציה:

  • צרו Client Component בשם ThemeProvider שמספק context של theme
  • צרו Client Component בשם ThemeToggle עם כפתור למעבר בין בהיר לכהה
  • ודאו שה-layout הראשי (Server Component) עוטף את כל האפליקציה ב-Provider
  • השתמשו בתבנית children כדי שדפי Server Component ימשיכו לעבוד

תרגיל 4 - דף פרופיל מורכב

צרו דף פרופיל (/profile) עם המבנה הבא:

  • הדף עצמו הוא Server Component ששולף את נתוני המשתמש
  • קומפוננטת ProfileHeader (Server) - מציגה שם ותמונה
  • קומפוננטת ProfileStats (Server) - מציגה סטטיסטיקות (פוסטים, עוקבים)
  • קומפוננטת EditProfileForm (Client) - טופס עריכה עם useState
  • קומפוננטת ProfileTabs (Client) - טאבים (פוסטים, תגובות, לייקים)

דמו את הנתונים מהשרת (אין צורך בבסיס נתונים אמיתי).


תרגיל 5 - גבולות סריאליזציה

תקנו את הבעיות בקוד הבא. כל אחד מהמקרים מנסה להעביר משהו שלא ניתן לסריאליזציה:

// מקרה 1
export default function Page() {
  const formatPrice = (price: number) => `${price} ש"ח`;
  return <PriceDisplay format={formatPrice} price={100} />;
}

// מקרה 2
export default function Page() {
  const settings = new Map([["theme", "dark"], ["lang", "he"]]);
  return <Settings data={settings} />;
}

// מקרה 3
export default function Page() {
  const regex = /^[a-z]+$/;
  return <Validator pattern={regex} />;
}

שאלות

  1. מה קורה כשמייבאים Server Component לתוך Client Component?
  2. למה Client Components עדיין עוברים SSR?
  3. מה ההבדל בין העברת Server Component כ-children לעומת יבוא ישיר ב-Client Component?
  4. איך "use client" משפיע על קבצים שמיובאים לתוך הקובץ?
  5. האם כל הקוד של Client Component רץ רק בדפדפן?