קומפוננטת ריאקט עם אירועים

למאמר הקודם בסדרה על ריאקט
למאמר הבא בסדרה על ריאקט

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

איך נדגים? תסתכלו על אפליקצית הריאקט הזו. היא סופרת קליקים. יש פה שתי קומפוננטות: ClickCounterDisplay שאחראית על התצוגה ועל ה-CSS ובתוכה, הס-פן-תעיר ישנה לה קומפוננטה זעירה בשם ClickCounter. כרגע מה שיש בה זה איתחול של state עם clicksNumber למספר 0.

כך יראה ה-HTML המלא:

0 Clicks

0
Clicks

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

הדבר הראשון שאני אוסיף הוא מתודה שתעלה את ה-this.state.clicksNumber ב-1 בקומפוננטת ClickCounter שמכילה את הנתון הזה. טוב, זה קל באמצעות this.setState:

class ClickCounter extends React.Component {
  constructor(props) {
    super(props);     
    this.state = {
      clicksNumber: 0,
    };
  }
  
  clickHandler() {
    this.setState({clicksNumber: this.state.clicksNumber+1});
  }
  
  render() {
    const content = <div>{ this.state.clicksNumber }</div> // This is JSX
    return content;
  }
}

אבל הפונקציה clickHandler לא ממש תעבוד בלי שמישהו יקרא לה. מי יקרא לה? כפתור פשוט עם אירוע onclick. כן, כן. נכון שחשבתם שזה יותר מסובך? נוסיף את הכפתור וב-onclick נקרא לפונקציה המיותמת clickHandler. כיוון שאנחנו יוצאים מהסקופינג, לא נשכח להוסיף bind. ככה הכל נראה:

class ClickCounter extends React.Component {
  constructor(props) {
    super(props);     
    this.state = {
      clicksNumber: 0,
    };
    this.clickHandler = this.clickHandler.bind(this);
  }
  
  clickHandler() {
    this.setState({clicksNumber: this.state.clicksNumber +1});
  }
  
  render() {
    const content = <div>
            { this.state.clicksNumber }
             <button onClick={this.clickHandler}>+</button>
    </div>
    return content;
  }
}

וזה גם יעבוד.

אבל רגע, חשבתם שזה הכל? חשוב להדגיש שה-onClick הזה הוא לא אירוע native של הדפדפן. אנחנו כאן בJSX ולא ב-HTML. בסוף הכל מרונדר לג׳אווהסקריפט אבל ה-onClick הזה הוא בעצם אירוע סינתטי ולא אירוע ׳אמיתי׳ שמגיע מה-DOM. למה? עניין של ביצועים (לא אחפור יותר מדי) אבל זה ממש חשוב להבנה. למה? כי אם אני רוצה להצמיד אירוע לקומפוננטת ריאקט, זה לא יעבוד. רוצים דוגמה? בטח שאתם רוצים. בואו ובמקום הכפתור המסכן שיש פה ב-JSX:

<button onClick={this.clickHandler}>+</button>

אני אצור קומפוננטה שכל מה שיש בה זה כפתור ואנסה להצמיד אליה אירוע:

class ClickCounterDisplay extends React.Component {
  render() {
    const bigStyle = {
      backgroundColor: 'black',
      borderRadius: 10,
      color: 'silver',
      fontSize: '42px',
      textAlign: 'center',
      width: 250,
    };
    const smallStyle = {
      color: 'gold',
      fontSize: '25px',
    };
    return <div style={bigStyle}>
        <ClickCounter />
        <div style={smallStyle}>Clicks</div>
      </div>
  }
}

class SomeButton extends React.Component {
  render() {
    return <span><button>+</button></span>
  }
}

class ClickCounter extends React.Component {
  constructor(props) {
    super(props);     
    this.state = {
      clicksNumber: 0,
    };
    this.clickHandler = this.clickHandler.bind(this);
  }
  
  clickHandler() {
    this.setState({clicksNumber: this.state.clicksNumber +1});
  }
  
  render() {
    const content = <div>
            { this.state.clicksNumber }
             <SomeButton onClick={this.clickHandler} />
    </div>
    return content;
  }
}

const target = document.getElementById('content');
ReactDOM.render(
  <ClickCounterDisplay />,
  target
);

כפי שאתם רואים יצרתי קומפוננטת SomeButton שאני קורא לה ב-JSX ומנסה להצמיד לה אירוע. מה הבעיה? שזה לא יעבוד. למה זה לא יעבוד? כי ה-onClick הוא אירוע סינתטי ולא אירוע ׳אמיתי׳. אי אפשר להצמיד אותו לקומפוננטות של ריאקט ישירות. אז איך כן עושים את זה? מאוד פשוט – עם handler. כלומר מעבירים את הפונקציה שמופעל מבחוץ כפרמטר. הקומפוננטה SomeButton תראה כך:

class SomeButton extends React.Component {
  render() {
    return <span><button onClick={this.props.clickHandler}>+</button></span>
  }
}

אני מקבל את ה-clickHandler מבחוץ כפרמטר. איך אני מעביר אותו? ובכן, כך:

<SomeButton clickHandler={this.clickHandler} />

See the Pen React component with state management & events on other component by Ran Bar-Zik (@barzik) on CodePen.

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

אהבתם? לא אהבתם? דרגו!

לא אהבתי בכלללא אהבתיבסדראהבתיאהבתי מאוד (2 הצבעות, ממוצע: 5.00 מתוך 5)

תגיות: פורסם בקטגוריה: ריאקט

יאללה, שתפו :)

אל תשארו מאחור! יש עוד מה ללמוד!

One comment on “קומפוננטת ריאקט עם אירועים
  1. יוסף הגיב:

    תודה רבה אחלה מאמר

כתיבת תגובה

האימייל לא יוצג באתר.

רישום