چرخه حیات (Lifecycle) در ری اکت (React)

17 اسفند 1397
درسنامه درس 7 از سری آموزش react (ری اکت)
react-lifecycle-feature

در این درس به چند تا از رایج ترین توابع چرخه حیات که می توانیم در کامپوننت های ری اکت از آن استفاده کنیم، می پردازیم و دلیل اهمیت انها و نحوه استفاده از هرکدام از این توابع را آموزش خواهیم داد.

در روز گذشته درباره کامپوننت های stateful صحبت کردیم و یاد گرفتیم که چطور این کامپوننت ها وضعیت درونی خودشان را نگهداری می کنند. در درس امروز قصد داریم کمی درباره نحوه کارکرد یک کامپوننت در یک اپلیکیشن صحبت کنیم.

درس امروز راجع به چرخه حیات (Lifecycle) کامپوننت ها است.

فریم ورک ری اکت تعدادی متد به ما می دهد تا توسط آن بتوانیم درهر زمان از چرخه حیات کامپوننت که خواستیم، قابلیت هایی را اضافه کنیم. به اولین متد چرخه حیات که در زیر آمده توجه کنید.

چارت چرخه حیات ری اکت (React Lifecycle)
چارت چرخه حیات ری اکت (React Lifecycle)

متدهای componentWillMount و componentDidMount

هنگامی که یک کامپوننت روی یک صفحه برنامه مان تعریف می شود، نمی توانیم بلافاصله به عنصرهای DOM آن دسترسی داشته باشیم، چون ما گره (عنصر)های مجازی تعریف کردیم.

بنابراین باید تا زمانی که کامپوننت خودش را بطور کامل در مرورگر قرار دهد (mount می شود)، صبر کنیم. اگر بخواهید یک سری قابلیت به هنگام قرار گرفتن کامپوننت در صفحه، به برنامه ی ری اکتی خود اضافه کنید باید دو نوع هوک (یا تابع) مختلف تعریف کنید. یک نوع از این توابع قبل از اینکه کامپوننت به طور کامل در صفحه قرار گیرد، اجرا می شود و نوع دیگر،  بعد از قرار گیری کامپوننت در صفحه اعمال خواهد شد.

mount (قرار گرفتن) به چه معنی است؟

چون ما توسط ری اکت، نمایش مجازی از عناصر DOM صفحه ایجاد کردیم، در این نمایش مجازی دقیقاً همان عنصر DOM واقعی نیستند. در عوض، یک نمایشی از عناصر DOM در حافظه ایجاد کردیم که توسط ری اکت نگهداری می شود.

هنگامی که از mount صحبت می کنیم، منظور ما همان روند تبدیل مولفه های مجازی به عناصر DOM واقعی است که توسط ری اکت در DOM صفحه قرار می گیرد.

این قابلیت برای کارهایی از قبیل واکشی (بازیابی) داده ها برای کامپوننت ها مفید است. برای مثال فرض کنید یک برنامه پیگیری فعالیت ها برای نمایش رویدادهای گیت هاب نوشته ایم. ما می خواهیم تنها زمانی این داده ها را لود کنیم که خود داده ها رندر شده باشند.

در قسمت های قبلی ما یک کامپوننت content برای نمایش لیست فعالیت ها(اکتیویتی) ایجاد کرده بودیم.

class Content extends React.Component {
  render() {
    const { activities } = this.props; // ES6 destructuring

    return (
      <div className="content">
        <div className="line" />

        {/* Timeline item */}
        {activities.map(activity => (
          <ActivityItem activity={activity} />
        ))}
      </div>
    );
  }
}

حال باید کامپوننت content را برای ساخت یک درخواست به آدرس رویدادهای سایت Github بروزرسانی کنیم و از پاسخی که این api برای ما ارسال می کند، اکتیویتی ها را نمایش دهیم و همچنین باید stateمان را بروزرسانی کنیم.

همان طور که در درس قبلی دیدید، با نسبت دادن یک آبجکت به this.state در متد سازنده یک کامپوننت می توانیم آن کامپوننت را stateful  کنیم.

class Content extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      activities: []
    };
  }

  // ...
}

حال هنگامی که خود کامپوننت به طور کامل در صفحه قرار گرفت (mount شد)، ما باید یک درخواست Http ارسال کنیم.

با تعریف تابع componentWillMount() (یا componentDidMount()) در کامپوننت، می توانیم آنها را بعد از اینکه کامپوننت در صفحه قرار گرفت، اجرا کنیم. این متدها بهترین مکان برای اضافه کردن یک درخواست Get هستند.

حال کامپوننت content را با ایجاد یک درخواست به api سایت github بروزرسانی می کنیم. چون می خواهیم تنها یک لیست کوچک را نمایش دهیم. بنابراین فقط چهار رویداد آخر را می گیریم.

ما یک سری داده را از سایت گیت هاب گرفته و آنها را در یک فایل استاتیک json ذخیره کرده ایم، و می خواهیم مستقیما داده های فایل را توسط promise به داخل برنامه لود کنیم (در درس های آینده اینکار را با Ajax انجام می دهیم).

اما اکنون می خواهیم روی چگونگی بروزرسانی کامپوننت ها با داده های جدید کار کنیم.

class Content extends React.Component {
  // ...
  componentWillMount() {
    this.setState({ activities: data });
  }
  // ...
}

دقت کنید که نیاز به تغییر دیگری در کامپوننت content نیست و به همین شکلی که هست، کار خواهد کرد.

متدهای componentWillUpdate و componentDidUpdate

گاهی اوقات می خواهیم بعضی از داده های کامپوننت مان را قبل یا بعد از رندر شدن کامپوننت، بروزرسانی کنیم. برای مثال فرض کنید می خواهیم یک تابع برای زمانی که کامپوننت درحال رندر شدن است و یا یک تابع برای موقعی که props یک کامپوننت تغییر کرد، فراخوانی کنیم.

متد componentWillUpdate برای مدیریت تغییرات یک کامپوننت، استفاده می شود (به شرطی که از this.setState برای مدیریت تغییرات استفاده نکنیم، چون در اینصورت یک حلقه بی نهایت در برنامه بوجود خواهد آمد).

یکی دیگر از متدهای چرخه حیات، متد componentWillReceiveProps است.

متد componentWillReceiveProps

هنگامی که کامپوننت یک props جدیدی دریافت کند، ری اکت یک متد را فراخوانی می کند.

این اولین متدی است که در هنگام دریافت یک props جدید، فراخوانی می شود. بهترین زمان برای تعریف این متد موقعی است که می خواهید محاسبات خاصی را روی بعضی از props ها، انجام دهیم و وضعیت داخلی کامپوننت تان را بروزرسانی کنیم. در این متد می توانیم stateمان را بسته به props های جدید بروزرسانی کنیم. چیزی که در این جا باید به آن توجه کنید این است که حتی اگر متد componentWillReceiveProps فراخوانی شود، مقدار props ممکن است تغییری نکند، در نتیجه بهتر است که تغییرات مقادیر props ها را همیشه بررسی کنید.

برای مثال یک دکمه refresh به لیست اکتیویتی تان اضافه کنید تا کاربران با کلیک روی آن، یک درخواست جدید برای دریافت رویدادها از سایت github ارسال می شود.

ما از متد componentWillReceiveProps به منظور بارگذاری مجدد داده های کامپوننت استفاده می کنیم و چون کامپوننت مان stateful است، می خواهیم این state را با داده های جدید بروزرسانی کنیم، بنابراین نمی توانیم تنها props یک کامپوننت را بروزرسانی کنیم. در اینجا باید از متد componentWillReceiveProps استفاده کرده تا به کامپوننت بگوییم که ما می خواهیم نرم افزار یک Refresh انجام دهد.

سپس یک دکمه به برنامه اضافه کرده و توسط آن یک prop به نام requestRefresh از نوع بولین به کامپوننت content ارسال می کنیم تا این کامپوننت خودش را رفرش کند.

class Container extends React.Component {
  constructor(props) {
    super(props);

    this.state = { refreshing: false };
  }

  // Bound to the refresh button
  refresh() {
    this.setState({ refreshing: true });
  }

  // Callback from the `Content` component
  onComponentRefresh() {
    this.setState({ refreshing: false });
  }

  render() {
    const { refreshing } = this.state;
    return (
      <div className="notificationsFrame">
        <div className="panel">
          <Header title="Github activity" />
          {/* refreshing is the component's state */}
          <Content
            onComponentRefresh={this.onComponentRefresh.bind(this)}
            requestRefresh={refreshing}
            fetchData={fetchEvents}
          />
          {/* A container for styling */}
          <Footer>
            <button onClick={this.refresh.bind(this)}>
              <i className="fa fa-refresh" />
              Refresh
            </button>
          </Footer>
        </div>
      </div>
    );
  }
}

المان <Footer />

در اینجا یک عنصر جدید داریم که فرزندان یک عنصر را نمایش می دهند. این الگویی است که به ما اجازه می دهد تا یک کلاس Css برای بعضی از محتواهای مان اضافه کنیم.

class Footer extends React.Component {
  render() {
    return <div className="footer">{this.props.children}</div>;
  }
}

با استفاده از این prop جدید (requestRefresh) می توانیم لیست اکتیویتی ها را از آبجکت State هنگامی که مقدارش تغییر می کند، بروزرسانی کنیم.

class Content extends React.Component {
  // ...
  componentWillReceiveProps(nextProps) {
    // Check to see if the requestRefresh prop has changed
    if (nextProps.requestRefresh === true) {
      this.setState({ loading: true }, this.updateData);
    }
  }
  // ...
}

این دمو از داده های استاتیکی که در یک فایل json قرار گرفته، استفاده می کند و هنگامی که رفرشی انجام می شود، بطور تصادفی چهار عنصر را از آن بر می داریم، با این کار در حقیقت یک رفرش را شبیه سازی کرده ایم.

متد componentWillUnmount

قبل از اینکه یک کامپوننت از حالت mount خارج شود (unmount شود)، ری اکت یک متد به نام componentWillUnmount فراخوانی می کند. از این متد می توانیم برای هر نوع عملیات پاکسازی از قبیل: پاکسازی متدهای timeout، پاکسازی داده ها، قطع اتصال های وب سوکت و ... استفاده کنیم.

برای مثال در کامپوننت clock که در قسمت های قبلی با آن کار کردیم، یک متد timeout تعریف کرده بودیم که در هر ثانیه یکبار اجرا می شد. هنگامی که کامپوننت آماده unmount می شود، می خواهیم مطمئن شویم که این متد timeout هم پاکسازی می شود، چون جاوا اسکریپت هنگامی که کامپوننت وجود ندارد (unmount شده)، دیگر متد timeout را اجرا نمی کند.

به کامپوننت timer که قبلاً آن را ایجاد کرده بودیم نگاهی بیندازید:

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = this.getTime();
  }

  componentDidMount() {
    this.setTimer();
  }

  setTimer() {
    this.timeout = setTimeout(this.updateClock.bind(this), 1000);
  }

  updateClock() {
    this.setState(this.getTime, this.setTimer);
  }

  getTime() {
    const currentTime = new Date();
    return {
      hours: currentTime.getHours(),
      minutes: currentTime.getMinutes(),
      seconds: currentTime.getSeconds(),
      ampm: currentTime.getHours() >= 12 ? "pm" : "am"
    };
  }

  // ...
  render() {}
}

ما می خواهیم هنگامی که ساعت (clock) آماده unmout می شود، timeoutیی که در داخل متد setTimer() در کامپوننت تعریف کرده ایم را حذف کنیم. استفاده از متد componentWillUnmout امکان هر گونه عملیات پاکسازی یا حذف این موارد را به ما می دهد.

class Clock extends React.Component {
  // ...
  componentWillUnmount() {
    if (this.timeout) {
      clearTimeout(this.timeout);
    }
  }
  // ...
}

در فریمورک ری اکت چندین متد چرخه حیات وجود دارند که ما می توانیم از آنها در برنامه ما استفاده کنیم.

ما از این متدها در هنگام ساخت برنامه های ری اکتی استفاده می کنیم، بنابراین بهتر است که با آنها آشنا شوید و بدانید که از این متدها در کدام مرحله از چرخه حیات یک کامپوننت باید استفاده کنید.

همچنین یک مفهوم جدیدی در این قسمت معرفی کردیم که می خواهیم نگاهی اجمالی به آن بیندازیم: یک متد کالبک روی کامپوننت تعریف کردیم که توسط کامپوننت فرزند به کامپوننت والدش فراخوانی می شود.

در قسمت بعدی می خواهیم ببینیم که چگونه می توان یک api برای propهای یک کامپوننت تعریف و مستندسازی کرد تا هنگامی که قصد اشتراک گذاری آن کامپوننت با تیم ها و یا یک برنامه دیگر را داشته باشید، بتوانید اینکار را انجام دهید.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری آموزش react (ری اکت) توصیه می‌کند:
نویسنده شوید

دیدگاه‌های شما (4 دیدگاه)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

khosro akbari
27 فروردین 1399
سلام من خیلی از سایتتون و آموزش هاتون استفاده کردم و میکنم و تشکر میکنم از زحمات شما برای آموزش!! با عرض پوزش ب نظرم خیلی بد این مبحث رو توضیح دادید یعنی برای من ک هنوز نمیدونم react ب چه صورت هست خیلی گنگ توضیح دادید خصوصا در مورد کد ها ک اصلا جایگذاری ها درست نیست بعد میایم جلوتر میبینم جایگذاری تغییر کرده شما صفحات قبل اصلا getTime رو تعریف نکردید و ازش تو رندر استفاده کردید لطفا ویرایش بشه چون واقعا وقتی توضیح رو میخونی و اجرا میگیری اصن جور درنمیاد و توضیح هم میتونه روون تر باشه لزومی نداره حتما تو 30 جلسه تموم بشه بشه 60 تا ولی خوب توضیح داده بشه!! ممنونم فقط ب عنوان یه دانش آموز خواستم نظرم رو بگم!!

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

mohstaba
26 فروردین 1399
componentWillMount منقضی شده است.

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

حسن فرجی
17 دی 1398
سلام چیزی به نام componentWillMount ندارم هم سایت رسمی react چک هم w3schools ،درستش کنید (منم هی کد میزدم توش میدیدم اجرا نمیشه بعد نیم ساعت سر درقمی فهمیدم وجود خارجی نداره این متد!)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

محمد
13 بهمن 1398
چرا چرخه componentWillMount داریم ..شما باید به آموزش های بیشتری در این مورد رجوع کنید و مقاله های بیشتری بخونید. اتفاقا در آموزش تصویری ای که من دارم میبینم چنین چیزی هست شما در کلاس اصلی یا کامپوننت های دیگری که دارین استفاده میکنین console.log('WillMount') //setcode بذارین خواهید دید که اجرا خواهد شد

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

رضا رجبی
31 اردیبهشت 1398
سلام ممنون بابت به اشتراک گذاری این مطلب جسارتا چند بار در متن نوشتید فریم ورک ری اکت در صورتی ک ری اکت یک کتابخونه است

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.