6.5 אירועים ורינדור מותנה הרצאה
אירועים בריאקט - Events¶
ריאקט מטפלת באירועים בצורה דומה ל-DOM, אבל עם כמה הבדלים:
- שמות אירועים ב-camelCase:
onClick,onChange,onSubmit(לאonclick,onchange) - מעבירים פונקציה כ-handler, לא מחרוזת:
onClick={handleClick}(לאonclick="handleClick()") - האירוע שמתקבל הוא SyntheticEvent של ריאקט - עוטף את האירוע המקורי של הדפדפן
function Button() {
const handleClick = () => {
console.log("Button clicked!");
};
return <button onClick={handleClick}>Click me</button>;
}
פונקציה inline לעומת handler נפרד¶
function Example() {
// separate handler - cleaner for complex logic
const handleClick = () => {
console.log("clicked");
};
return (
<div>
<button onClick={handleClick}>Separate handler</button>
{/* inline - fine for simple, one-line handlers */}
<button onClick={() => console.log("clicked")}>Inline handler</button>
</div>
);
}
העברת ארגומנטים ל-handler¶
כשצריך להעביר ארגומנט ל-handler, עוטפים אותו בפונקציית חץ:
function ItemList() {
const items = ["apple", "banana", "cherry"];
const handleItemClick = (item: string) => {
console.log("Selected:", item);
};
return (
<ul>
{items.map((item) => (
<li key={item}>
{/* wrap in arrow function to pass the argument */}
<button onClick={() => handleItemClick(item)}>{item}</button>
</li>
))}
</ul>
);
}
טעות נפוצה - קריאה לפונקציה במקום העברתה:
// WRONG - calls handleClick immediately during render!
<button onClick={handleClick("hello")}>Click</button>
// CORRECT - passes a function that will call handleClick when clicked
<button onClick={() => handleClick("hello")}>Click</button>
אובייקט האירוע - Event Object¶
ה-handler מקבל אובייקט אירוע עם מידע שימושי:
function Form() {
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault(); // prevent page reload
console.log("Form submitted");
};
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
console.log("Click position:", e.clientX, e.clientY);
console.log("Target element:", e.target);
console.log("Current target:", e.currentTarget);
};
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
console.log("Key pressed:", e.key);
if (e.key === "Enter") {
console.log("Enter key pressed");
}
};
return (
<form onSubmit={handleSubmit}>
<input onKeyDown={handleKeyDown} placeholder="Type here..." />
<button onClick={handleClick}>Submit</button>
</form>
);
}
אירועים נפוצים¶
| אירוע | מתי מופעל |
|---|---|
onClick |
לחיצה |
onChange |
שינוי ערך (input, select, textarea) |
onSubmit |
שליחת טופס |
onKeyDown / onKeyUp |
לחיצה/שחרור מקש |
onFocus / onBlur |
כניסה/יציאה מפוקוס |
onMouseEnter / onMouseLeave |
כניסה/יציאה של העכבר |
onDoubleClick |
לחיצה כפולה |
מניעת התנהגות ברירת מחדל - preventDefault¶
כמו ב-vanilla JS, preventDefault() מונע את ההתנהגות הרגילה:
function Link() {
const handleClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
e.preventDefault(); // prevent navigation
console.log("Link clicked, but not navigating");
};
return <a href="https://example.com" onClick={handleClick}>Click me</a>;
}
רינדור מותנה - Conditional Rendering¶
ריאקט מאפשרת להציג תוכן שונה לפי תנאים. יש כמה דרכים לעשות זאת.
אופרטור AND - &&¶
מציג את הצד הימני רק אם הצד השמאלי הוא truthy:
function Notification({ count }: { count: number }) {
return (
<div>
<h1>Dashboard</h1>
{count > 0 && <p>You have {count} new notifications</p>}
</div>
);
}
כשה-count הוא 0 או שלילי, הפסקה לא מוצגת.
מלכודת ה-0 עם &&¶
זהירות! כש-0 נמצא בצד השמאלי של &&, ריאקט מציגה "0" במקום כלום:
// BUG: when count is 0, renders "0" on screen
{count && <p>You have {count} notifications</p>}
// FIX: explicitly convert to boolean
{count > 0 && <p>You have {count} notifications</p>}
// OR use Boolean()
{Boolean(count) && <p>You have {count} notifications</p>}
הסיבה: 0 && <p>...</p> מחזיר 0 (לא false), וריאקט מרנדרת 0 כטקסט. false && <p>...</p> מחזיר false שריאקט מתעלמת ממנו.
אופרטור טרנרי - Ternary¶
מציג תוכן אחד אם התנאי אמת, ואחר אם שקר:
function LoginStatus({ isLoggedIn }: { isLoggedIn: boolean }) {
return (
<div>
{isLoggedIn ? (
<p>Welcome back!</p>
) : (
<p>Please log in.</p>
)}
</div>
);
}
טרנרי טוב למקרים פשוטים של "או זה או זה". למקרים מורכבים יותר, עדיף דרכים אחרות.
החזרה מוקדמת - Early Return¶
כשיש תנאי פשוט שמשנה את כל ה-UI, אפשר להחזיר JSX שונה מוקדם:
function UserProfile({ user }: { user: User | null }) {
if (!user) {
return <p>Loading...</p>;
}
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}
זה שימושי במיוחד למצבי טעינה (loading), שגיאות (error), וחוסר נתונים (empty state).
משתנה JSX¶
אפשר לחשב את ה-JSX לפני ה-return ולשמור אותו במשתנה:
function StatusBadge({ status }: { status: "active" | "inactive" | "pending" }) {
let badge: React.ReactNode;
if (status === "active") {
badge = <span style={{ color: "green" }}>Active</span>;
} else if (status === "inactive") {
badge = <span style={{ color: "red" }}>Inactive</span>;
} else {
badge = <span style={{ color: "orange" }}>Pending</span>;
}
return <div>Status: {badge}</div>;
}
זה טוב כשיש יותר משני מצבים - ternary מקונן הופך ללא קריא.
map של תנאים למחלקות CSS¶
function Alert({ type }: { type: "info" | "warning" | "error" }) {
const classNames: Record<string, string> = {
info: "alert-info",
warning: "alert-warning",
error: "alert-error",
};
return <div className={classNames[type]}>Alert content</div>;
}
שילוב - אירועים עם רינדור מותנה¶
דוגמה שמשלבת אירועים ורינדור מותנה:
import { useState } from "react";
function Accordion({ title, children }: { title: string; children: React.ReactNode }) {
const [isOpen, setIsOpen] = useState(false);
return (
<div style={{ border: "1px solid #ddd", borderRadius: "8px", marginBottom: "8px" }}>
<button
onClick={() => setIsOpen(!isOpen)}
style={{ width: "100%", padding: "12px", textAlign: "left", cursor: "pointer" }}
>
{title} {isOpen ? "[-]" : "[+]"}
</button>
{isOpen && (
<div style={{ padding: "12px" }}>{children}</div>
)}
</div>
);
}
function App() {
return (
<div>
<Accordion title="Section 1">
<p>Content of section 1.</p>
</Accordion>
<Accordion title="Section 2">
<p>Content of section 2.</p>
</Accordion>
</div>
);
}
סיכום¶
- אירועים בריאקט משתמשים ב-camelCase ומקבלים פונקציה (לא מחרוזת)
- מעבירים ארגומנטים ל-handler עם פונקציית חץ:
onClick={() => fn(arg)} e.preventDefault()מונע התנהגות ברירת מחדל- רינדור מותנה עם
&&: הצגה רק אם תנאי מתקיים (זהירות מ-0) - רינדור מותנה עם ternary: או זה או זה
- early return: החזרת JSX שונה בתחילת הפונקציה
- משתנה JSX: חישוב התוכן לפני ה-return עם if/else