התחלה מהירה
ברוכים הבאים לתיעוד של תגובה! הדף ייתן לכם היכרות עם 80% מהמושגים ב-React תשתמשו ביום-יום.
You will learn
- איך ליצור קומפוננטות ולקנן ביניהן
- איך להוסיף סימון (סימון) ועיצוב (סגנונות)
- איך להציג נתונים
- איך לרנדר תנאים ורשימות
- איך להגיב לאירועים ולעדכן את המסך
- איך לשתף נתונים בין קומפוננטות
יצירה וקינון של קומפוננטות
אפליקציות React בנויות מ-קומפוננטות. קומפוננטה היא חלק מה-UI (ממשק משתמש) שיש לו לוגיקה ומראה משל עצמו. קומפוננטה יכולה להיות קטנה כמו כפתור, או גדולה כמו עמוד שלם.
קומפוננטות React הן פונקציות JavaScript שמחזירות סימון (סימון):
function MyButton() {
return (
<button>I'm a button</button>
);
}עכשיו אחרי שהגדרתם את MyButton, אפשר לקנן אותה בתוך קומפוננטה אחרת:
export default function MyApp() {
return (
<div>
<h1>Welcome to my app</h1>
<MyButton />
</div>
);
}שימו לב ש-<MyButton /> מתחיל באות גדולה. כך מזהים קומפוננטת React. שמות קומפוננטות React חייבים להתחיל באות גדולות, בעוד שתגיות HTML חייבות להיות באותיות קטנות.
הנה התוצאה:
function MyButton() { return ( <button> I'm a button </button> ); } export default function MyApp() { return ( <div> <h1>Welcome to my app</h1> <MyButton /> </div> ); }
המילים ייצוא ברית מחדל מציינות את הקומפוננטה טפסים בקובץ. אם חלק מתחביר JavaScript לא מוכר לכם, ל-MDN ול-javascript.info יש מקורות מעולים.
כתיבת סימון עם JSX
תחביר הסימון (סימון) שראיתם למעלה נקראת JSX. הוא אופציונלי, אבל רוב פרויקטי React users בו בגלל הנוחות שלו. כל הכלים שאנו ממליצים עליהם לפיתוח מקומי תומך ב-JSX מהקופסה.
JSX מחמיר יותר מ-HTML. צריך לסגור תגיות כמו <br />. הקומפוננטה שלכם גם לא יכולה להחזיר כמה תגיות JSX נפרדות. צריך לתת להם בהורה משותף, כמו <div>`...`</div> או עטיפה ריקה <>...</>:
function AboutPage() {
return (
<>
<h1>About</h1>
<p>Hello there.<br />How do you do?</p>
</>
);
}אם יש לכם הרבה HTML להמיר ל-JSX, אפשר להשתמש ב-ממיר אונליין.
הוספת עיצובים
ב-React מגדירים מחלקת CSS בעזרת className. זה עובד כמו המאפיין class של HTML:
<img className="avatar" />לאחר כותבים את כללי ה-CSS בקובץ CSS נפרד:
/* In your CSS */
.avatar {
border-radius: 50%;
}תגובה לא מכתיבה איך להוסיף קובצי CSS. במקרה הפשוט ביותר, תגית <link> ל-HTML. אם אתם משתמשים בכלי בנייה (כלי בנייה) או בפריימורק (מסגרת), בדקו בתיעוד שלהם איך להוסיף קובץ CSS לפרויקט.
הצגת נתונים
JSX יכול להכניס סימון (סימון) ל-JavaScript. סוגרים מסולסלים מאפשרים “לחזור” ל-JavaScript כדי להטמיע מהקוד ולהציג אותו למשתמש. לדוגמה, זה יציג את user.name:
return (
<h1>
{user.name}
</h1>
);אפשר גם “לברוח ל-JavaScript” מתוך מאפיינים JSX, אבל צריך להשתמש בסוגריים מסולסלים במקום מירכאות. למשל, className="avatar" מעביר את המחרוזת "avatar" כמחלקת CSS, אבל src={user.imageUrl} קורא את הערך של השינוי user.imageUrl ב-JavaScript, ואז מעביר אותו למאפיין src:
return (
<img
className="avatar"
src={user.imageUrl}
/>
);אפשר לשים גם ביטויים מורכבים יותר סוגריים מסולסלים של JSX, למשל שרשור מחרוזות:
const user = { name: 'Hedy Lamarr', imageUrl: 'https://i.imgur.com/yXOvdOSs.jpg', imageSize: 90, }; export default function Profile() { return ( <> <h1>{user.name}</h1> <img className="avatar" src={user.imageUrl} alt={'Photo of ' + user.name} style={{ width: user.imageSize, height: user.imageSize }} /> </> ); }
בדוגמה למעלה, style={{}} הוא לא תחביר מיוחד, אלא אובייקט {} רגיל בתוך סוגריים מסולסלים של style={ } ב-JSX. אפשר להשתמש במאפיין סגנון עיצובים תלויים במשתני JavaScript.
רינדור מותנה
ב-React אין תחביר מיוחד לתנאי תנאי. במקום זה משתמשים באותן טכניקות של JavaScript רגיל. לדוגמה, אפשר להשתמש במשפט if כדי לכלול את JSX בתנאי:
let content;
if (isLoggedIn) {
content = <AdminPanel />;
} else {
content = <LoginForm />;
}
return (
<div>
{content}
</div>
);אם מעדיפים קוד תמציתי יותר, אפשר להשתמש ב-אופרטור תנאי ?. צריך ל-אם, הוא עובד בתוך JSX:
<div>
{isLoggedIn ? (
<AdminPanel />
) : (
<LoginForm />
)}
</div>כשלא צריך ענף else, אפשר להשתמש גם בתחביר קצר של אופרטור לוגי &&:
<div>
{isLoggedIn && <AdminPanel />}
</div>כל ההגישות האלה עובדות גם למנות של מאפיינים (תכונות). אם חלק מהתחביר הזה של JavaScript לא מוכר לכם, אפשר להתחיל תמיד עם אם...אחר.
רינדור רשימות
תשתמשו ביכולות JavaScript כמו for loop ופונקציית [מערך map()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Ob/Global lists_Ob) קומספו/Global_Ob רשימות/Global_Ob רשימות.
לדוגמה, נניח שיש לכם מערך של מוצרים:
const products = [
{ title: 'Cabbage', id: 1 },
{ title: 'Garlic', id: 2 },
{ title: 'Apple', id: 3 },
];בתוך הקומפוננטה, השתמשו ב-map() כדי ליצור עוד מוצרים למערך פריטי <li>:
const listItems = products.map(product =>
<li key={product.id}>
{product.title}
</li>
);
return (
<ul>{listItems}</ul>
);שימו לב של-<li> יש מאפיין (תכונה) בשם מפתח. עבור כל פריט ברשימה, צריך להעביר מחרוזת או מספר שמזה את הפריט בצורה ייחודית לאחים שלו. בדרך כלל מפתח מגיע מהנתונים, כמו ID ממסד נתונים. React Usert ב-keys לדעת מה קרה אם ירצה עוד, מוחקים או שנים סדר של פריטים.
const products = [ { title: 'Cabbage', isFruit: false, id: 1 }, { title: 'Garlic', isFruit: false, id: 2 }, { title: 'Apple', isFruit: true, id: 3 }, ]; export default function ShoppingList() { const listItems = products.map(product => <li key={product.id} style={{ color: product.isFruit ? 'magenta' : 'darkgreen' }} > {product.title} </li> ); return ( <ul>{listItems}</ul> ); }
תגובה לאירועים
אפשר להגיב לאירועים על ידי הגדרת פונקציות מטפל באירועים בתוך הקומפוננטות:
function MyButton() {
function handleClick() {
alert('You clicked me!');
}
return (
<button onClick={handleClick}>
Click me
</button>
);
}שימו לב של-onClick={handleClick} אין סוגרים בסוף. אל תקראו לפונקציית המטפל בעצמכם, צריך רק להעביר אותה. תגיב תקרא למטפל כשהמשתמש ילחץ על הכפתור.
עדכון המסך
לעתים קרובות תרצו שהקומפוננטה “תזכור” מידע ותציג אותו. למשל, אפשר לספור כמה פעמים נלחץ כפתור. כדי לעשות את זה, משתמשים ב-state.
קודם מייבאים את useState מ-React:
import { useState } from 'react';עכשיו אפשר להגדיר משתנה state בתוך הקומפוננטה:
function MyButton() {
const [count, setCount] = useState(0);
// ...useState מחזיר שני דברים: ה-state הנוכחי (count) ופונקציה שמעדכנת אותו (setCount). אפשר לתת להם כל שם, אבל הקונבנציה היא [משהו, setSomething].
בפעם הראשונה שהכפתור מוצג, count יהיה 0 כי העברתם 0 ל-useState(). כשרוצים לשנות, קוראים ל-setCount() ומעבירים אליו את הערך החדש. לחיצה על הכפתור תגדיל את המונה:
function MyButton() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<button onClick={handleClick}>
Clicked {count} times
</button>
);
}תגובה תקרא לפונקציית הקומפוננטה שוב. הפעם ספירה תהיה 1. אחר כך 2, וכן הלאה.
אם מרנדרים את אותה קומפוננטה כמה פעמים, כל מופע יקבל state משלו. נסו ללחוץ על כל כפתור בנפרד:
import { useState } from 'react'; export default function MyApp() { return ( <div> <h1>Counters that update separately</h1> <MyButton /> <MyButton /> </div> ); } function MyButton() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); } return ( <button onClick={handleClick}> Clicked {count} times </button> ); }
לב שכל כפתור “זוכר” את ה-count שלו, ולא משפיע על הכפתורים האחרים.
שימוש ב-Hooks
לפונקציות שמתחילות ב-use קוראים Hooks. useState הוא Hook מובנה ש-React מספקת. אפשר למצוא Hooks מובנים נוספים ב-מדריך ה-API. אפשר גם לכתוב Hooks משלכם על ידי שילוב Hooks קיימים.
ל-Hooks יש מגבלות מחמירות יותר מפונקציות אחרות. אפשר לקרוא ל-Hooks רק בראש הקומפוננטות (או Hooks אחרים). אם להשתמש ב-useState בתוך תנאי או לולאה, צריך לחלץ קומפוננטה חדשה ולהשתמש בו שם.
שיתוף נתונים בין קומפוננטות
בדוגמה הקודמת, לכל MyButton היה count עצמאי, וכשלחצו על כפתור רק ה-count של אותו כפתור השתנה:


בהתחלה, ה-count של כל MyButton הוא 0


ה-MyButton הראשון מעדכן את ה-count שלו ל-1
עם זאת, הרבה פעמים צריך שקומפוננטות ישתפו נתונים ויתעדכנו יחד תמיד.
כדי ששתי קומפוננטות MyButton יציגו את אותו count ויתעדכנו יחד, צריך להרים את ה-state מהכפתורים למעלה אל הקומפוננטה הקרובה שמכילה את שתיהן.
בדוגמה הזו זו MyApp:


בהתחלה, ה-count של MyApp הוא 0, והוא מועבר לשני הילדים


בלחיצה, MyApp מעדכנת את ה-count ל-1 ומעבירה אותו לשני הילדים
עכשיו, כשלוחצים על אחד הכפתורים, ה-ספירה ב-MyApp מסתובבת, וזה משנה את שני ה-counts בתוך MyButton. כך עושים את זה בקוד.
קודם מעבירים את ה-state למעלה מ-MyButton ל-MyApp:
export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>Counters that update separately</h1>
<MyButton />
<MyButton />
</div>
);
}
function MyButton() {
// ... we're moving code from here ...
}לאחר מעבירים את ה-state למטה מ-MyApp לכל MyButton, יחד עם מטפל בלחיצה משותף. אפשר להעביר מידע ל-MyButton באמצעות סוגריים מסולסלים ב-JSX, בדיוק כמו שעשינו קודם עם תגיות מובנות כמו <img>:
export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>Counters that update together</h1>
<MyButton count={count} onClick={handleClick} />
<MyButton count={count} onClick={handleClick} />
</div>
);
}למידע שמעבירים כך קוראים props. עכשיו MyApp מחזיקה את ה-state בשם count ואת מטפל האירוע handleClick, ו-מעבירה את שניהם כ-props לכל אחד מהכפתורים.
לבסוף, משנים את MyButton כך ש-תקרא את ה-props שעברו מקומפוננטת ההורה שלה:
function MyButton({ count, onClick }) {
return (
<button onClick={onClick}>
Clicked {count} times
</button>
);
}כשאתם לוחצים על כפתור, מטפל האירוע onClick מופעל. ה-prop onClick של כל כפתור מצביע לפונקציה handleClick בתוך MyApp, ולכן הקוד שלה רץ. הקוד הזה קורא ל-setCount(count + 1) ומעדכן את ה-state בשם count. הערך החדש של count מועבר כ-prop לכל כפתור, כך שכולם מציגים את אותו ערך. לזה קוראים “להרים state למעלה” (lifting state up).
import { useState } from 'react'; export default function MyApp() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); } return ( <div> <h1>Counters that update together</h1> <MyButton count={count} onClick={handleClick} /> <MyButton count={count} onClick={handleClick} /> </div> ); } function MyButton({ count, onClick }) { return ( <button onClick={onClick}> Clicked {count} times </button> ); }
השלבים הבאים
הזה אתם כבר מכירים את היסודות של כתיבת קוד ב-React!
עברו ל-המדריך כדי לתרגל ולבנות את המיני-אפליקציה הראשונה שלכם ב-React.