Menu

קומפוננטות React: קומפוננטות פונקציה עם דוגמאות

קומפוננטת React היא פונקציית JavaScript שמחזירה JSX. למדו איך כותבים קומפוננטות פונקציה ואיך קוראים להן, איך מרכיבים מהן עץ, מפצלים אותן לקבצים, שומרים עליהן טהורות, ובמה קומפוננטה שונה מאלמנט.

בדף הזה יש עורכים שאפשר להריץ - לערוך, להריץ ולראות את הפלט מיד.

קומפוננטת React היא פונקציית JavaScript שמחזירה JSX: חלק UI לשימוש חוזר, כמו כפתור, כרטיס או דף שלם. משתמשים בה כמו בתגית HTML, <Profile />, ו-React קוראת לפונקציה כדי לדעת מה לשים על המסך. אפליקציות נבנות על ידי הכנסת קומפוננטות לתוך קומפוננטות אחרות.

App מרנדרת את Profile פעמיים, וכל Profile מרנדרת Avatar. שנו את ראשי התיבות בתוך Avatar ושני הפרופילים מתעדכנים, כי יש להם הגדרה משותפת אחת. כרגע כל האנשים ברשימה זהים; הדף הבא, props, מראה איך מעבירים לכל עותק נתונים משלו.

כתיבת קומפוננטה

לקומפוננטת פונקציה יש שתי דרישות:

  1. השם שלה מתחיל באות גדולה: Profile, לא profile.
  2. היא מחזירה משהו ש-React יודעת לרנדר: JSX, מחרוזת, מספר, null (לא לרנדר כלום) או מערך של אלה.
function Welcome() {
    return <h1>Welcome back</h1>;
}

// Arrow functions work the same way
const Welcome = () => <h1>Welcome back</h1>;

כשה-JSX משתרע על כמה שורות, עטפו אותו בסוגריים אחרי return. בלעדיהם, return שאחריו ירידת שורה מחזיר undefined, וכל מה שאחריו מתעלמים ממנו.

למה השם חייב להתחיל באות גדולה

JSX מסתכל על האות הראשונה של התגית. אות קטנה פירושה אלמנט HTML מובנה, כך ש-<div> נשאר <div>. אות גדולה פירושה "משתנה שנמצא ב-scope", כך ש-<Profile /> קורא לפונקציה Profile שלכם. תנו לקומפוננטה שם באות קטנה ו-React תיצור במקום זאת אלמנט HTML לא מוכר עם השם הזה:

השורה השנייה מציגה רק את התווית שלה, והקונסול מציג רק Greeting ran. React הכניסה לדף תגית <greeting> ריקה ואף פעם לא קראה לפונקציה עם האות הקטנה. build של פיתוח גם מזהיר ש-The tag <greeting> is unrecognized in this browser; התצוגה המקדימה רצה כמו build של פרודקשן, אז רואים רק את הטקסט החסר. שנו את שם הפונקציה ל-Greetings ואת התגית ל-<Greetings /> כדי לתקן.

הרכבת קומפוננטות

קומפוננטות נועדו להיות מקוננות. דף הוא עץ: App למעלה, אחריה חלקי layout, ואז חלקים קטנים יותר עד כפתורים בודדים. כל קומפוננטה מכירה רק את החלקים שהיא מרנדרת ישירות, כך שאפשר לחשוב על כל אחת בנפרד.

לכל LikeButton יש state משלו, כך שלייק לפוסט אחד לא משפיע על האחרים. כדי להוסיף כפתור שיתוף לכל פוסט, כותבים אותו פעם אחת ומוסיפים <ShareButton /> בתוך Post.

מתי לפצל קומפוננטה

אין כלל קבוע, אבל כמה סימנים אומרים שחלק מסוים ראוי לקומפוננטה משלו: אותו markup מופיע בשני מקומות, לקטע ב-JSX יש state משלו (כמו כפתור הלייק שלמעלה), או שהפונקציה התארכה עד שצריך לגלול כדי לראות את ה-return שלה. פיצול לפי הקווים האלה שומר כל קומפוננטה קטנה מספיק כדי לקרוא אותה במסך אחד. פיצול מוקדם מדי עולה מעט: קומפוננטה היא רק פונקציה, ולכן קל לאחד שתיים בחזרה.

ייצוא וייבוא של קומפוננטות

העורכים כאן מכילים קובץ אחד, אבל בפרויקט אמיתי כל קומפוננטה נמצאת בקובץ משלה. לקובץ יכול להיות default export אחד וכל מספר של named exports:

// Avatar.jsx
export default function Avatar({ initials }) {
    return <div className="avatar">{initials}</div>;
}

// Badge.jsx
export function Badge({ label }) {
    return <span className="badge">{label}</span>;
}
export function NewBadge() {
    return <Badge label="new" />;
}
// Profile.jsx
import Avatar from './Avatar.jsx';
import { Badge, NewBadge } from './Badge.jsx';

export default function Profile() {
    return (
        <div>
            <Avatar initials="AL" />
            <Badge label="admin" />
            <NewBadge />
        </div>
    );
}

default export אפשר לייבא בכל שם; named export מייבאים בתוך סוגריים מסולסלים בשם המדויק שלו. צוותים בדרך כלל בוחרים סגנון אחד ונצמדים אליו. שמות הקבצים בדרך כלל תואמים לקומפוננטה: Avatar.jsx מייצא את Avatar.

שמרו על קומפוננטות טהורות

React מצפה שקומפוננטה תתנהג כמו פונקציה טהורה בזמן הרינדור: אותם props ו-state נותנים אותו JSX, והרינדור לא משנה שום דבר שהיה קיים לפני שהוא רץ. React עשויה לרנדר קומפוננטה פעמים רבות, בזמנים שאתם לא שולטים בהם, ולכן קומפוננטה שעורכת משתנים חיצוניים בזמן הרינדור מייצרת פלט שונה בכל פעם.

הכוסות הלא טהורות מתחילות ב-1, 2, 3. לחצו על הכפתור: שום דבר לא השתנה באורחים, ובכל זאת הרשימה הלא טהורה מציגה עכשיו 4, 5, 6, כי כל רינדור הוסיף למשתנה המשותף guest. הכוסות הטהורות מקבלות את המספר שלהן מ-props ונשארות נכונות. בפיתוח, Strict Mode מרנדר כל קומפוננטה פעמיים כדי לחשוף בדיוק באג כזה; התצוגה המקדימה רצה כמו build של פרודקשן, אז כאן הסטייה מופיעה רק כשמרנדרים שוב.

לשנות דברים זה בסדר, רק לא בזמן הרינדור. עדכנו state ב-event handlers, ודברו עם העולם החיצוני (טיימרים, מנויים, כותרת המסמך) באפקטים.

קומפוננטות מול אלמנטים

ה-קומפוננטה היא הפונקציה, Profile. אלמנט הוא מה ש-JSX יוצר כשכותבים <Profile />: אובייקט קטן שאומר "רנדר את Profile עם ה-props האלה". React יוצרת אלמנטים, קוראת לקומפוננטות שהם מציינים, והופכת את התוצאה ל-DOM. אף פעם לא קוראים לקומפוננטה בעצמכם בתור Profile(); כותבים <Profile /> ונותנים ל-React לקרוא לה, כדי שתוכל לעקוב אחרי ה-state שלה ואחרי המקום שלה בעץ.

המקום הזה חשוב. הדוגמה הזו מגדירה קומפוננטה בתוך קומפוננטה אחרת, טעות נפוצה:

הקלידו משהו, ואז לחצו על הכפתור: הטקסט שלכם נעלם. כל רינדור של App יוצר פונקציית NameField חדשה לגמרי, ולכן React רואה סוג קומפוננטה אחר במקום הזה וזורקת את הישנה יחד עם ה-state שלה. העבירו את NameField אל מעל App, לרמה העליונה של הקובץ, והטקסט שורד כל לחיצה. הדף על רינדור מסביר איך React מחליטה מה לשמור.

קומפוננטות פונקציה וקומפוננטות class

לפני שהוקים הגיעו ב-React 16.8, קומפוננטות שהיו צריכות state נכתבו כ-classes:

import { Component } from 'react';

class Welcome extends Component {
    render() {
        return <h1>Hello, {this.props.name}</h1>;
    }
}

קומפוננטות class עדיין עובדות ב-React 19, ותפגשו אותן בקוד ישן וב-error boundaries, שעדיין דורשים class. קוד חדש משתמש בקומפוננטות פונקציה עם הוקים כמו useState ו-useEffect, שעושים את אותן עבודות עם פחות קוד. הדף על קומפוננטות class ממפה כל יכולת של class להוק המתאים לה.

שאלות נפוצות

מה זו קומפוננטה ב-React?

קומפוננטה היא חלק UI לשימוש חוזר שנכתב כפונקציית JavaScript שמחזירה JSX. משתמשים בה כמו בתגית HTML, <Profile />, ו-React קוראת לפונקציה כדי לדעת מה לצייר.

למה שמות של קומפוננטות React חייבים להתחיל באות גדולה?

JSX משתמש באות הראשונה כדי להחליט מה התגית. תגית באות קטנה כמו <profile /> נחשבת לאלמנט HTML בשם profile, והפונקציה שלכם אף פעם לא נקראת. תגית באות גדולה כמו <Profile /> מפנה לקומפוננטה שלכם.

מה ההבדל בין קומפוננטות פונקציה לקומפוננטות class?

שתיהן מתארות UI. קומפוננטות פונקציה הן פונקציות רגילות ומשתמשות בהוקים בשביל state ואפקטים; קומפוננטות class יורשות מ-React.Component ומשתמשות במתודות כמו render ו-componentDidMount. קוד חדש משתמש בקומפוננטות פונקציה.

מה זו קומפוננטה טהורה ב-React?

קומפוננטה טהורה מחזירה אותו JSX עבור אותם props ו-state ולא משנה שום דבר מחוץ לעצמה בזמן הרינדור. React סומכת על זה כדי לרנדר קומפוננטות בכל פעם שהיא צריכה, בלי הפתעות.

אפשר להגדיר קומפוננטה בתוך קומפוננטה אחרת?

עדיף שלא. קומפוננטה שמוגדרת בתוך אחרת היא פונקציה חדשה בכל רינדור, ולכן React מתייחסת אליה כאל קומפוננטה אחרת בכל פעם ומאפסת את ה-state שלה. הגדירו קומפוננטות ברמה העליונה של הקובץ.

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל