Menu

קומפוננטות class ב-React: state, מחזור חיים, המרה

קומפוננטת class היא class של JavaScript שיורשת מ-React.Component ומחזירה JSX ממתודת render. למדו את this.props, this.state ו-setState, קשירת event handlers, מתודות מחזור חיים, PureComponent, ואיך ממירים class לקומפוננטת פונקציה.

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

קומפוננטת class היא class של JavaScript שיורשת מ-React.Component ומחזירה JSX ממתודת render(). היא קוראת props מ-this.props, מחזיקה state ב-this.state, ומעדכנת אותו עם this.setState(). קומפוננטות פונקציה עם הוקים החליפו אותן בקוד חדש, אבל classes עדיין נתמכות במלואן, מופיעות בהרבה בסיסי קוד ישנים, והן הדרך היחידה לכתוב error boundary.

כל מונה שומר state משלו. הוסיפו <Counter label="Plums" /> שלישי וגם הוא מתחיל ב-0.

האנטומיה של קומפוננטת class

import { Component } from 'react';

class Welcome extends Component {
    static defaultProps = { name: 'stranger' };

    constructor(props) {
        super(props); // required before using this
        this.state = { visits: 1 };
    }

    render() {
        return <h1>Hello, {this.props.name}. Visit #{this.state.visits}</h1>;
    }
}
  • ה-class יורש מ-Component (או מ-React.Component עם import React from 'react').
  • render() הוא חובה. הוא חייב להיות טהור, כמו הגוף של קומפוננטת פונקציה: קוראים את this.props ואת this.state, ומחזירים JSX.
  • this.props מחזיק את ה-props. הם לקריאה בלבד.
  • אפשר לקבוע state ב-constructor (קודם קוראים ל-super(props)) או, נפוץ יותר היום, כ-class field: state = { visits: 1 };.
  • static defaultProps עדיין עובד ב-classes ב-React 19 (הוא הוסר רק מקומפוננטות פונקציה).

this.setState ממזג, ויכול לקבל updater

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

"+3 with objects" מוסיף אחד, כי כל שלוש הקריאות קוראות את אותו this.state.likes. "+3 with updaters" מוסיף שלושה. "Move to Paris" שומר על name ועל likes (המיזוג) אבל מאבד את zip, כי המיזוג הוא ברמה אחת בלבד. כתבו address: { ...this.state.address, city: 'Paris' } כדי לשמור אותו. הארגומנט השני האופציונלי של setState רץ אחרי העדכון, והקונסול מציג שם את הכתובת החדשה.

קשירת event handlers

מתודה שמועברת בתור onClick={this.handleClick} נקראת אחר כך כפונקציה רגילה, בלי האובייקט שלה, ולכן this בתוכה הוא undefined.

הכפתור הראשון רושם TypeError על קריאת setState של undefined. השני עובד, כי פונקציית חץ ב-class field לוכדת את this כשהמופע נוצר. התיקון הישן יותר, שעדיין נפוץ בקוד legacy, קושר ב-constructor:

constructor(props) {
    super(props);
    this.state = { on: false };
    this.handleClick = this.handleClick.bind(this);
}

פונקציית חץ inline, onClick={() => this.handleClick()}, גם עובדת.

מתודות מחזור חיים

classes מגיבות ל-mounting, לעדכון ול-unmounting דרך מתודות עם שמות קבועים. אלה שתראו הכי הרבה:

  • componentDidMount(): אחרי שהרינדור הראשון ב-DOM. מתחילים טיימרים, מנויים, בקשות.
  • componentDidUpdate(prevProps, prevState): אחרי כל עדכון. השוו לערכים הקודמים לפני שאתם עושים עבודה, אחרת תיכנסו ללולאה.
  • componentWillUnmount(): לפני הסרה. מבטלים את מה ש-componentDidMount התחיל.
  • shouldComponentUpdate(nextProps, nextState): מחזירים false כדי לדלג על רינדור.

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

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

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

ואותה קומפוננטה כפונקציה. כל מתודת מחזור חיים הופכת לחלק מאפקט, ו-setup ו-cleanup קשורים יושבים זה ליד זה במקום בשתי מתודות.

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

  1. this.props.x הופך ל-prop שעובר destructuring, { x }.
  2. כל מפתח של this.state הופך ל-useState משלו. זכרו שה-setter מחליף במקום למזג.
  3. מתודות הופכות לפונקציות רגילות בתוך הקומפוננטה. לא צריך קשירה.
  4. componentDidMount, componentDidUpdate ו-componentWillUnmount הופכים לקריאות useEffect, מקובצות לפי מה שהן עושות ולא לפי מתי הן רצות.
  5. createRef הופך ל-useRef, ו-static contextType עם this.context הופכים ל-useContext או ל-use.

השאירו error boundaries כ-classes; אין להם מקבילה בפונקציות.

PureComponent

קומפוננטת class רגילה מתרנדרת בכל פעם שההורה שלה מתרנדר. PureComponent משווה קודם את ה-props וה-state החדשים לקודמים, רמה אחת לעומק, ומדלג על הרינדור כששום דבר לא השתנה. זה המקביל ב-class ל-React.memo.

לחצו על הכפתור: רק PlainLabel rendered נרשם, כי PureLabel רואה את אותו text. העבירו text={'hello ' + clicks} לשתיהן ושתיהן מתרנדרות בכל לחיצה.

ההשוואה רדודה, ולכן prop שהוא אובייקט או פונקציה חדשים בכל רינדור של ההורה (style={{ color: 'red' }}, onClick={() => ...}) מכשיל אותה. זו אותה מלכודת כמו עם React.memo.

דברים ש-React 19 הסירה מ-classes

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

  • string refs (ref="input" עם this.refs.input). השתמשו ב-createRef() או ב-ref callback.
  • legacy context (contextTypes, childContextTypes, getChildContext). השתמשו ב-createContext עם static contextType.
  • propTypes מתעלמים מהם. השתמשו ב-TypeScript או בבדיקות משלכם.
  • findDOMNode נעלם. שימו ref על אלמנט ה-DOM במקום.

גם המתודות הישנות componentWillMount, componentWillReceiveProps ו-componentWillUpdate הן legacy. הן עדיין רצות, גם תחת השמות הישנים וגם תחת שמות ה-UNSAFE_ (UNSAFE_componentWillMount וכן הלאה), אבל הן מיושנות ו-StrictMode מזהיר עליהן; העבירו את הקוד שלהן ל-componentDidMount, componentDidUpdate או getDerivedStateFromProps.

שאלות נפוצות

האם קומפוננטות class הוצאו משימוש ב-React?

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

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

קומפוננטת class מחזיקה state ב-this.state, מעדכנת אותו עם this.setState, ומגיבה למחזור החיים דרך מתודות עם שם. קומפוננטת פונקציה משתמשת בהוקים (useState, useEffect) לאותן עבודות, לא צריכה this, והיא קצרה יותר.

האם setState מעדכן את ה-state מיד?

לא. this.setState מתזמן עדכון ו-React מרנדרת מאוחר יותר, כך ש-this.state עדיין מחזיק את הערך הישן מיד אחרי הקריאה. העבירו פונקציה, this.setState((state) => ...), כשהערך החדש תלוי בישן, או קראו את התוצאה ב-callback של הארגומנט השני או ב-componentDidUpdate.

למה this הוא undefined ב-event handler שלי?

מתודת class שמועברת בתור onClick={this.handleClick} נקראת בלי האובייקט שלה, ולכן this הוא undefined. הגדירו את ה-handler כפונקציית חץ ב-class field (handleClick = () => { ... }) או קשרו אותו ב-constructor.

מה זה PureComponent?

Component שמדלג על רינדור כשה-props וה-state שלו שווים בהשוואה רדודה לקודמים. זו גרסת ה-class של React.memo.

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

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

להתחיל