همه چیز در مورد کار کردن با رویداد یا Event در React

دسته بندی: آموزش
زمان مطالعه: 8 دقیقه
۲۳ آذر ۱۳۹۷

همه چیز در مورد کار کردن با رویداد یا Event در Reactدر این مطلب میخوام کار کردن با رویداد یا Event در React رو بهتون آموزش بدم تا بتونین با استفاده از اون Application خودتون رو مدیریت کنید.

بیشتر رفتارهایی که Application ما از خودش نشون میده بر پایه رویدادها هست و رویدادها این رفتارها رو مدیریت میکنه. مثلا چند مورد از این رویدادها بصورت زیر هستند:

  • کاربر مقداری رو در فرم ثبت نام وارد میکنه
  • کاربر بر روی دکمه ثبت یا Submit کلیک میکنه
  • و ...

رویدادها به روشهای مختلفی trigger میشن و ما در App به اونا گوش میدیم تا پاسخ مناسبی به هر کدام از اونا بدیم. اگر با Javascript خالص کار میکنید، به احتمال زیاد با تعریف و مدیریت رویدادها آشنا هستید ولی کار با رویدادها در React مقداری متفاوت و متمایز هست که در ادامه بصورت کامل آموزش داده میشه.

به وجود آوردن رویداد یا Event در React

در ابتدا یک فرم ساده رو به وجود میاریم که یک input و یک دکمه در اون وجود دارد. زمانی که مقداری رو در input وارد میکنیم، رویدادی trigger میشه. با کلیک کردن بر روی دکمه یک تابع فراخوانی میشه که متن درون input رو معکوس یا برعکس میکنه.

نحوه کارکرد این فرم بصورت زیر است:

  • یک input خالی به کاربر این امکان رو میده که یک متن رو در اون وارد بکنه.
  • رویداد onChange زمانی که مقداری در input وارد بشه، trigger میشه. این رویداد باعث فراخوانی متد handleChange میشه و در اون مقدار وارد شده در state قرار میگیره.
  • زمانی که دکمه Reverse text کلیک میشه، یک رویداد دیگه trigger میشه و اینبار متد handleReverse فراخوانی میشه.

کد مربوط به این فرم بصورت زیر خواهد بود:

class App extends React.Component {
  state = {
    /*  Initial State */
    input: "",
    reversedText: ""
  };

  /* handleChange() function to set a new state for input */
  handleChange = event => {
    const value = event.target.value;
    this.setState({
      input: value
    });
  };

  /* handleReverse() function to reverse the input and set that as new state for reversedText */
  handleReverse = event => {
    event.preventDefault();
    const text = this.state.input;
    this.setState({
      reversedText: text
        .split("")
        .reverse()
        .join("")
    });
  };

  render() {
    return (
      <React.Fragment>
        { /* handleReverse() is called when the form is submitted */ }
        <form onSubmit={this.handleReverse}>
          <div>
            { /* Render input entered */}
            <label>Text: {this.state.input}</label>
          </div>
          <div>
           { /* handleChange() is triggered when text is entered */ }
            <input
              type="text"
              value={this.state.input}
              onChange={this.handleChange}
              placeholder="Enter a text"
            />
          </div>
          <div>
            <button>Reverse Text</button>
          </div>
        </form>
        { /* Render reversed text */}
        <p>Reversed Text: {this.state.reversedText}</p>
      </React.Fragment>
    );
  }
}

خروجی کد بالا بصورت زیر هست:

گوش دادن یا listen کردن به رویدادهای Component

فرض کنید که یک Component ساده بصورت زیر داریم:

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

این Component رو بصورت زیر در App خودمون وارد میکنیم. به نظر شما اینجوری کار میکنه؟

class App extends React.Component{
  state = {
    count: 0
  }

  handleIncrement = (event) => {
    this.setState({ count: this.state.count + 1})
  }

  render() {
    return(
      <React.Fragment>
        <h1>{this.state.count}</h1>
        <IncrementButton onClick={this.handleIncrement} />
      </React.Fragment>
    )
  }
}

اگر خروجی کد بالا رو ببینید، خواهید دید که هر چه بر روی + کلیک کنیم، عدد 0 بیشتر نمیشه و همون صفر میمونه. ما فقط میتونیم رویدادها رو برای المنتهای DOM تعریف کنیم. در کد بالا ما رویداد onClick رو برای کامپوننت ساخته شده خودمون قرار دادیم و این رویداد کار نمیکنه.

برای اینکه بتونیم رویدادهای Component یا Children مدیریت کنیم، یک راه ساده این هست که متد مورد نظر رو به عنوان props به Component پاس بدیم و در اون Component، کارهای مورد نظرمون رو انجام بدیم. پس کدها رو بصورت زیر تغییر میدیم:

class IncrementButton extends React.Component{
  render() {
    return (
      <React.Fragment>
        <button onClick={this.props.increaseButton}>+</button>
      </React.Fragment>
    )
  }
}

class App extends React.Component{
  state = {
    count: 0
  }

  handleIncrement = (event) => {
    this.setState({ count: this.state.count + 1})
  }

  render() {
    return(
      <React.Fragment>
        <h1>{this.state.count}</h1>
        <IncrementButton increaseButton={this.handleIncrement} />
      </React.Fragment>
    )
  }
}

حالا اگر در خروجی بر روی + کلیک کنید، عدد مورد نظر یکی یکی اضافه خواهد شد. میتونین خروجی رو ببینید: شما همچنین میتونین Component مورد نظر رو بصورت Stateless تعریف کنید. بصورت زیر:

const IncrementButton = (props) => {
  return (
    <React.Fragment>
      <button onClick={props.increaseButton}>+</button>
    </React.Fragment>
  )
}

خروجی بصورت قبل خواهد بود.

اضافه کردن Event listener

ممکنه بعضی وقتا پیش بیاد که بخواید که رویداد خاصی از DOM رو در زمان Mount شدن کامپوننت trigger کنید. مثلا فرض کنید که بخوایم یک رویداد resize برای window تعریف کنیم تا بتونیم عرض مرورگر رو با تغییر سایز مرورگر به دست بیاریم. کد زیر رو ببینید:

class App extends React.Component{
  state = {
    windowWith: window.innerWidth
  }

  handleResize = (event) => {
    this.setState({ windowWith: window.innerWidth })
  }

  render() {
    return(
      <React.Fragment>
        <h1>Window Width</h1>
        <h1>{this.state.windowWith}</h1>
      </React.Fragment>
    )
  }
}

اگر ما بصورت بالا عمل کنیم و به این صورت رویداد رو تعریف کنیم، این رویداد هیچوقت trigger نخواهد شد. در این موارد باید در زمان Mount شدن component، رویداد مورد نظرمون رو تعریف کرده و callback رو نیز برای اون قرار بدیم. برای اینکار بصورت زیر عمل میکنیم:

class App extends React.Component{
  state = {
    windowWith: window.innerWidth
  }

  handleResize = (event) => {
    this.setState({ windowWith: window.innerWidth })
  }
  
  componentDidMount() {
    window.addEventListener('resize', this.handleResize)
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.handleResize)
  }

  render() {
    return(
      <React.Fragment>
        <h1>Window Width</h1>
        <h1>{this.state.windowWith}</h1>
      </React.Fragment>
    )
  }
}

همونطور که میبینید در componentDidMount که یکی از life cycle‌های React هست، یک رویداد resize برای window تعریف کردیم و this.handleResize رو به عنوان Callback برای اون قرار دادیم. در componentWillUnmount هم با استفاده از removeListener این رویداد رو حذف کردیم تا باعث memory leak نشه و مشکلی به وجود نیاد.

خروجی کد بالا بصورت زیر خواهد بود:

خلاصه و نتیجه‌گیری

همونطور که دیدید React بصورت مستقیم به رویدادهای DOM متصل نمیشه و با استفاده از رویدادهای مصنوعی یا Synthetic Events که یک wrapper برای رویدادهای DOM هستند، کارهای خودش رو انجام میده. لینکهای زیر که برگرفته از مستندات React هستند رو میتونین برای مطالعه بیشتر ببینید:

چه امتیازی به این مقاله می دید؟
نویسنده محمد اسفندیاری
بسیار به طراحی وب علاقمندم و به سرعت در حال یادگیری تمام مباحث پیشرفته هستم و دوست دارم که به دیگران هم یاد بدهم.

نظرات کاربران

علیرضا

عالی بود. البته اونجا که گفتید از کامپوننت Stateless استفاده در واقع به نظر من بهتره بگیم از کامپوننت فانکشنال بیس استفاده میکنیم. چون همانطور که میدونید کامپوننت فانکشنال بیس هم میتونه با استفاده از useState از استیت ها استفاده کنه که بهش hook هم میگن.

نازنین کریمی مقدم

سلام.
بله حق با شماست شاید اینجا کلمه فانکشنال عبارت درست‌تری باشه. نویسنده ما با آوردن کلمه stateless قصد داشته تا هدفش از نوشتن کد رو نشون بده و اون بخش از کد رو برای این نوشته که stateless بشه.
خیلی ممنون که با ما همراه هستید 🙂

تهرومز

مطلب مفیدی بود

MAHSA LAHZE

ممنون از مقاله خوبتون

محمد اسفندیاری

موفق باشید دوست عزیز

ارسال دیدگاه
خوشحال میشیم دیدگاه و یا تجربیات خودتون رو با ما در میون بذارید :