רשימות ומפתחות

ראשית, בואו נסקור איך לשנות רשימות ב-JavaScript.

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

const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((number) => number * 2);
console.log(doubled);

הקוד הזה ידפיס [2, 4, 6, 8, 10] לקונסול.

ב-React שינוי מערכים לרשימות של אלמנטים הוא כמעט זהה.

רינדור קומפוננטות מרובות

אתה יכול לבנות אוסף של אלמנטים ולכלול אותם ב-JSX באמצעות סוגריים מסולסלים {}.

למטה, אנו רצים על numbers מערך המספרים באמצעות פונקציית ()map ב-JavaScript. אנו מחזירים <li> אלמנט לכל פריט. לבסוף, אנו מקצים את המערך החוזר ל-listItems:

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
  <li>{number}</li>
);

אנו מכלילים את המערך listItems כולו לתוך אלמנט <ul>, ומרדנדרים את ה-DOM.

ReactDOM.render(
  <ul>{listItems}</ul>,
  document.getElementById('root')
);

נסו זאת ב-CodePen

הקוד הזה מציג רשימה של מספרים מ-1 עד 5.

קומפוננטת רשימה בסיסית

בדרך כלל אנו נרנדר רשימה בתוך קומפוננטה.

אנחנו יכולים לשכתב את הדוגמה הקודמת לקומפוננטה שמקבלת numbers מערך של מספרים ומדפיסה רשימה של אלמנטים.

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li>{number}</li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

כשאר תריץ את הקוד הזה, תופיע אזהרה שמפתח צריך להיות מסופק לפריטים ברשימה. “מפתח” הוא תוכנה מיוחדת מסוג מחרוזת שאתה צריך להכליל מתי שאתה יוצר רשימה של אלמנטים. נדון מדוע זה חשוב בחלק הבא.

בואו נקצה key לרשימת הפריטים שלנו בתוך numbers.map() ונתקן את בעיית חסרון המפתח.

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li key={number.toString()}>
      {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

נסו זאת ב-CodePen

מפתחות

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

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
  <li key={number.toString()}>
    {number}
  </li>
);

הדרך הטובה ביותר לבחור מפתח היא להשתמש במחרוזת שמזהה באופן ייחודי פריט מהרשימה בין אחיו. לרוב תבחר ID מהנתונים שלך כמפתח:

const todoItems = todos.map((todo) =>
  <li key={todo.id}>
    {todo.text}
  </li>
);

כאשר אין לך ID קבוע לרנדור הפריטים, אתה רשאי להשתמש באינדקס של האיבר כמפתח בתור מוצא אחרון:

const todoItems = todos.map((todo, index) =>
  // קבוע ID עשה זאת אך ורק אם לפריט אין 
  <li key={index}>
    {todo.text}
  </li>
);

אנחנו לא ממליצים להשתמש באינדקסים עבור מפתחות אם סדר הפריטים ישתנה. זה יכול להשפיע לרעה על הביצועים ולגרום לבעיות ב-state של הקומפוננטה. עיין במאמר של Robin Pokorny בשביל הסבר מעמיק על ההשפעות השליליות של שימוש באינדקס כמפתח. אם תבחר לא להקצות מפתח מפורש לפריט ברשימה אז React ישתמש כברירת מחדל באינדקס כמפתח.

הנה הסבר מעמיק על למה מפתחות נחוצים אם אתה מעוניין ללמוד יותר.

חילוץ קומפוננטות עם מפתחות

מפתחות הגיוניים רק בהקשר של מערכים.

לדוגמה, אם אתה מחלץ קומפוננטת ListItem, אתה תעדיף לשמור את המפתח באלמנט <ListItem /> שבמערך מאשר באלמנט <li> שב-ListItem עצמו.

דוגמה: שימוש לא נכון במפתח

function ListItem(props) {
  const value = props.value;
  return (
    // טעות! אין צורך לציין את המפתח כאן
    <li key={value.toString()}>
      {value}
    </li>
  );
}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    // טעות! אתה צריך לציין את המפתח כאן
    <ListItem value={number} />
  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

דוגמה: שימוש נכון במפתח

function ListItem(props) {
  // נכון! אין צורך לציין את המפתח כאן
  return <li>{props.value}</li>;
}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    // נכון! יש לציין את המפתח בתוך המערך
    <ListItem key={number.toString()}
              value={number} />
  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

נסו זאת ב-CodePen

כלל אצבע טוב הוא שאלמנטים בתוך map() צריכים מפתחות.

מפתחות חייבים להיות ייחודיים בין אחים.

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

function Blog(props) {
  const sidebar = (
    <ul>
      {props.posts.map((post) =>
        <li key={post.id}>
          {post.title}
        </li>
      )}
    </ul>
  );
  const content = props.posts.map((post) =>
    <div key={post.id}>
      <h3>{post.title}</h3>
      <p>{post.content}</p>
    </div>
  );
  return (
    <div>
      {sidebar}
      <hr />
      {content}
    </div>
  );
}

const posts = [
  {id: 1, title: 'שלום עולם', content: '!React ברוכים הבאים ללמידת'},
  {id: 2, title: 'התקנה', content: 'npm-מ React אתה יכול להתקין את'}
];
ReactDOM.render(
  <Blog posts={posts} />,
  document.getElementById('root')
);

נסו זאת ב-CodePen

מפתחות משרתים כרמז ל-React אבל הם אינם עוברים לקומפוננטות שלך. אם אתה צריך את אותו הערך בקומפוננטה שלך, העבר אותו בצורה מפורשת כ-prop עם שם אחר.

const content = posts.map((post) =>
  <Post
    key={post.id}
    id={post.id}
    title={post.title} />
);

עם הדוגמה למטה, קומפוננטת Post יכולה לקרוא את props.id אבל לא את props.key.

הטמעת ()map בתוך JSX

בדוגמאות למעלה הצהרנו על משתנה נפרד listItems וכללנו אותו ב-JSX:

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <ListItem key={number.toString()}
              value={number} />
  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

JSX מאפשר להטמיע כל ביטוי בסוגריים מסולסלים כדי שנוכל להטביע את תוצאת map():

function NumberList(props) {
  const numbers = props.numbers;
  return (
    <ul>
      {numbers.map((number) =>
        <ListItem key={number.toString()}
                  value={number} />
      )}
    </ul>
  );
}

נסו זאת ב-CodePen

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