7.6 דפוסי תכנון וביצועים תרגול
תרגול - דפוסי תכנון וביצועים - Design Patterns and Performance¶
תרגיל 1 - Compound Components - Select מותאם¶
צרו קומפוננטת Select מותאמת אישית בדפוס Compound Components.
דרישות:
- קומפוננטות: Select, Select.Trigger, Select.Options, Select.Option
- שיתוף state דרך context (ערך נבחר, פתוח/סגור)
- תמיכה ב-placeholder, disabled, ו-onChange callback
- סגירה על לחיצה מחוץ לקומפוננטה
- תמיכה בניווט מקלדת (חיצים, Enter, Escape)
תרגיל 2 - HOC מתקדם¶
צרו שני HOC-ים שימושיים.
דרישות:
- withLogger - HOC שמדפיס ל-console כל רנדר של הקומפוננטה, כולל שם הקומפוננטה, props, וזמן הרנדר
- withPermission - HOC שמציג את הקומפוננטה רק אם למשתמש יש הרשאה מתאימה, אחרת מציג הודעה
- הדגימו שימוש בשני ה-HOC-ים על אותה קומפוננטה (הרכבה)
תרגיל 3 - Render Props - Data Fetcher¶
צרו קומפוננטת DataFetcher שמשתמשת ב-Render Props.
דרישות:
- מקבלת URL ו-render prop
- מנהלת מצבים: loading, error, data
- תמיכה ב-refetch
- תמיכה ב-polling (שליפה חוזרת כל X שניות)
- הדגימו שימוש עם שתי קומפוננטות שונות שמציגות את הנתונים בדרכים שונות
תרגיל 4 - אופטימיזציית ביצועים¶
קבלו את הקומפוננטה הבאה שיש בה בעיות ביצועים. תקנו אותה.
function ProductDashboard() {
const [products, setProducts] = useState(generateProducts(1000));
const [search, setSearch] = useState("");
const [sortBy, setSortBy] = useState("name");
const [selectedId, setSelectedId] = useState<number | null>(null);
const [theme, setTheme] = useState("light");
const filteredProducts = products
.filter((p) => p.name.toLowerCase().includes(search.toLowerCase()))
.sort((a, b) => (a[sortBy] > b[sortBy] ? 1 : -1));
const stats = {
total: filteredProducts.length,
avgPrice: filteredProducts.reduce((sum, p) => sum + p.price, 0) / filteredProducts.length,
maxPrice: Math.max(...filteredProducts.map((p) => p.price)),
};
return (
<div className={theme}>
<button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
החלף ערכת נושא
</button>
<input value={search} onChange={(e) => setSearch(e.target.value)} />
<div>סה"כ: {stats.total}, ממוצע: {stats.avgPrice.toFixed(0)}</div>
<ul>
{filteredProducts.map((product) => (
<ProductItem
key={product.id}
product={product}
isSelected={product.id === selectedId}
onSelect={() => setSelectedId(product.id)}
style={{ backgroundColor: theme === "light" ? "#fff" : "#333" }}
/>
))}
</ul>
</div>
);
}
function ProductItem({ product, isSelected, onSelect, style }) {
console.log(`Rendering: ${product.name}`);
return (
<li onClick={onSelect} style={{ ...style, fontWeight: isSelected ? "bold" : "normal" }}>
{product.name} - {product.price} ש"ח
</li>
);
}
דרישות:
- זהו את כל בעיות הביצועים
- תקנו כל בעיה עם הסבר
- השתמשו ב-useMemo, useCallback, React.memo ככל שנדרש
- הוכיחו ש-ProductItem מרונדר פחות פעמים אחרי התיקון
תרגיל 5 - Compound Components - Form Builder¶
צרו מערכת בניית טפסים בדפוס Compound Components.
דרישות:
- קומפוננטות: Form, Form.Field, Form.Input, Form.Select, Form.TextArea, Form.Submit, Form.Error
- ה-Form מנהל את כל ה-state והולידציה דרך context
- כל Field מרגיש "חלק" מהטופס ומדווח על שגיאות
- Form.Submit מושבת כשיש שגיאות ולידציה
- תמיכה בולידציה מותאמת לכל שדה
- הדגימו טופס יצירת משתמש עם שדות מגוונים
תרגיל 6 - רשימה וירטואלית (מתקדם)¶
ממשו רשימה וירטואלית בסיסית בעצמכם (ללא ספרייה).
דרישות:
- הציגו רשימה עם 10,000 פריטים
- רנדרו רק את הפריטים הנראים על המסך (+ buffer)
- תמכו בגלילה חלקה
- תמכו בפריטים בגבהים שונים
- הציגו מונה של כמה פריטים מרונדרים בפועל
- השוו ביצועים לעומת רשימה רגילה (הדגימו את ההבדל)
שאלות¶
- מה היתרון של Compound Components על פני העברת כל האפשרויות כ-props לקומפוננטה אחת?
- מתי Render Props עדיין מתאים יותר מהוק מותאם אישית?
- מה ההבדל בין React.memo לבין useMemo? מתי נשתמש בכל אחד?
- האם React.memo משווה props באופן עמוק (deep) או רדוד (shallow)?
- מה ה-trade-off של שימוש ב-virtualization? מתי לא כדאי להשתמש?