برسی دقیق و کامل چرخه‌ی حیات(Lifecycle) در ری‌اکت

ری‌اکت (React) چیست؟

ری‌اکت یک کتابخانه‌ی جاوا اسکریپت برای ساخت رابط کاربری است. برای شروع یک پروژه با ری‌اکت می‌توانید از آموزش زیر استفاده کنید.

استفاده از ری اکت بدون Node.js

چرا باید از متدهای چرخه‌ی حیات استفاده کنیم؟

چرخه‌ی حیات در ری‌اکت
چرخه‌ی حیات در ری‌اکت

در اطراف ما همه چیز از طریق یک چرخه‌ی تولد شروع می‌شود، بعد از تولد شروع به رشد (به‌روزرسانی) می‌کند و در یک نقطه نابود می‌شود مانند درختان، یک نرم‌افزار، خود ما انسان‌ها و یا یک Component در ری‌اکت، همه‌ی این‌ موارد به وجود می‌آیند، رشد و تغییر می کنند و در یک نقطه نابود می‌شوند.

متد‌های چرخه‌ی حیات (Lifecycle)، متد‌هایی هستند که برای دسترسی به هر یک از مراحل تولد تا نابودی یک Component مورد استفاده قرار می گیرند. فرض کنید می‌خواهید یک برنامه مشابه یوتیوب بسازید. که این برنامه از اینترنت برای لود کردن ویدئو و از باتری به عنوان منبع تغذیه استفاده می‌کند.

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

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

وقتی در یک پروژه تعداد component ها زیاد می‌شود. این خیلی مهم است که هر component وقتی کار خود را انجام داد نابود شود و دیگر از منابع استفاده نکند.

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

نمودار چرخه‌ی حیات در ری‌اکت
نمودار چرخه‌ی حیات در ری‌اکت

به طور کلی می‌توان چرخه‌ حیات در ری‌اکت را به سه مرحله تقسیم کرد:

  • نصب کردن (Mounting)
  • به‌روزرسانی (Updating)
  • نابودی (Unmounting)

خوب وقتشه که تک تک این مراحل رو با هم برسی کنیم:

مرحله اول: نصب کردن

در ری‌اکت نصب کردن به معنی بارگذاری component در DOM است.

این مرحله شامل مجموعه‌ای از متدها است که موقع مقدار دهی اولیه component و بارگذاری آن در DOM فراخوانی می‌شوند.

متدها به ترتیب زیر فراخوانی می‌شوند:

1- Constructor

هر وقت یک component ساخته می‌شود اولین متدی که فراخوانی می‌شود constructor است. این متد فقط یکبار در طول چرخه‌ حیات فراخوانی می‌شود. ما از این متد برای تعریف مقادیر و state استفاده می‌کنیم.

constructor() {
  super();
  this.state = {
    name: 'Jon Snow',
    age: 22
  }
} 

در ری‌اکت constructor تنها جایی است که می توان از this.state استفاده کرد، در بقیه متدها فقط می‌توان با استفاده از this.setState مقدار آن را تغییر داد.

2- static getDerivedStateFromProps

متد getDerivedStateFromProps درست قبل از render فراخوانی می‌شود. این متد می‌تواند یک Object برای به‌روزرسانی state و یا مقدار null را برای جلوگیری از به‌روزرسانی بازگرداند.

ما وقتی از این متد استفاده می‌کنیم که بخواهیم state خود را به وسیله‌ی props به‌روزرسانی کنیم.

این یک متد static است پس به کلید واژه‌ی this دسترسی ندارد. این متد می‌تواند به state و props دسترسی داشته باشد. از این رو وقتی یک state وابسته به props تعریف می‌کنیم با استفاده از این متد می‌توانیم آن را به‌روزرسانی کنیم.

this.state = { name: 'Harry' };

static getDerivedStateFromProps ( nextProps, prevState ) {
   if (prevState.name !== nextProps.name) {
     return {
       name: nextProps.name
     }
   }
   return null;
}

در مثال بالا ابتدا یک متغیر state با نام name و مقدار 'Harry' تعریف کرده‌ایم، با پاس دادن آرگومان‌های nextProps و prevState به getDerivedStateFromProps به props جدید و state موجود دسترسی پیدا کردیم و سپس با استفاده از دستور if چک می‌کنیم که اگر مقدار props جدید با state موجود متفاوت بود آن را به‌روزرسانی کن و اگر با هم مساوی بودند نیاز به به‌روزرسانی نیست و مقدار null را بازگردانده می‌شود.


3- render

این یک متد ضروری در component های ری‌اکت است، در این متد المنت‌ها آماده‌ی نصب در DOM می‌شوند.

در زیر یک مثال ساده از متد render در ری‌اکت را مشاهده می‌کنید:

 render() {
   return (
     <div>
       <h1>Hello World!</h1>
     </div>
   )
 }

همانطور که در مثال بالا مشاهده می‌کنید، متد render یک JSX را برای نمایش در UI باز می‌گرداند. یک متد render می‌تواند وقتی چیزی برای نمایش ندارد مقدار null را بازگرداند.

4- componentDidMount

بعد از این که ما برای اولین بار component خود را render کردیم این متد فراخوانی می‌شود.

در این متد ما می‌توانیم به DOM دسترسی داشته باشیم، اگر هم بخواهیم یک کتابخانه مانند Highcharts یا D3 به پروژه‌ی خود اضافه کنیم از این متد استفاده می‌کنیم.

componentDidMount() { 
  const modal = document.getElementById('modal');
  window.addEventLisener('click', () => { 'some code to close modal' });
} 


یکی دیگر از مهم‌ترین کاربردهای این متد استفاده از آن برای درخواست های Ajax و API است.

componentDidMount() {
  fetch('url')
    .then(response => response.json() );
    .then(data => this.setState({ info: data }) );
}


مرحله دوم: به‌روزرسانی

1- static getDerivedStateFromProps

همان گونه که در تصویر بالا نمودار چرخه‌ی حیات را مشاهده می‌کنید. می‌توانید ببینید که متد getDerivedStateFromProps در مرحله اول و دوم مشرک است. البته کارایی این متد در این مرحله بیشتر است.

اگر احتیاج دارید که state خود را با تغییرات props به‌روزرسانی کنید. می‌توانید با بازگرداندن یک Object در این متد این کار را انجام دهید.

* البته ناگفته نماند که معمولا بروزرسانی state توسط props توصیه نمی‌شود. و باید به عنوان آخرین راه‌حل از آن استفاده کرد.


2- shouldComponentUpdate

زمانی که یک props جدید دارید یا از ()setState استفاده می‌کنید، component شما به طور خودکار توسط ری‌اکت دوباره رندر می‌شود. تا شما بتوانید تغییرات را در UI مشاهده کنید.

اما با استفاده از این متد شما می‌توانید به component خود اجازه ندهید که دوباره رندر شود.

به طور کلی این متد وقتی می‌تواند مفید باشد که شما نمی‌خواهید ری‌اکت تغییرات جدید state و props را رندر کند.

شما نمی‌توانید در این متد از ()setState برای به‌روزرسانی state استفاده کنید.

shouldComponentUpdate(nextProps, nextState) {
    return this.props.title !== nextProps.title || this.state.input !== nextState.input;
}

همان طور که در مثال بالا مشاهده می‌کنید این متد مقادیر nextProps و nextState را به عنوان آرگومان می‌پذیرد و باید یک Boolean را در جواب سوال "آیا باید دوباره رندر کنم؟" بازگرداند که به طور پیش فرض مقدار true را باز می‌گرداند.


3- render

در این بخش component شما دوباره رندر می‌شود.


4- getSnapshotBeforeUpdate

متد ()getSnapshotBeforeUpdate یکی دیگر از متد‌های چرخه‌ی حیات ری‌اکت است که به تازگی معرفی شده و برای امنیت بیشتر جایگیزین متد ()componentWillUpdate شد.

getSnapshotBeforeUpdate(revProps, prevState) {
  // ...
}

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

یادتون باشه که این متد به ندرت استفاده می‌شود یا اصلا استفاده نمی‌شود. مگر این که بخواهید به یکی از attribute های DOM دسترسی داشته باشید و اون رو به عنوان آرگومان به ()componentDidUpdate پاس بدهید.

5- componentDidUpdate

حالا که به این بخش رسیدیم یعنی تغییرات ما در DOM اعمال شد. بیشترین مورد استفاده از این متد برای به‌روزرسانی DOM با تغییرات props و state است.

در این متد ما به سه چیز دسترسی داریم، props موجود، State موجود و مقداری که متد getSnapshotBeforeUpdate بازگردانده است.

componentDidUpdate(prevProps, prevState, snapshot) {
     if (this.props.userName !== prevProps.userName) {
          this.fetchData(this.props.userName);
     }
}

در مثال بالا ما مقدار props جدید را با props موجود مقایسه کردیم و اگر مقدار آن متفاوت بود آن را به fetchData پاس می‌دهیم.


مرحله 3: نابودی

این مرحله فقط شامل یک متد به نام ()componentWillUnmount است. همان طور که از نامش پیداست این متد قبل از نابود شدن component اجرا می‌شود. اگر نیاز به هرگونه عملیات پاکسازی برای component خود دارید می‌توانید از این متد استفاده کنید.

شما در این متد اجازه‌ی استفاده از ()setState برای تغییر state را ندارید.

به عنوان مثال برای این متد، وقتی که می‌خواهید یک ثانیه شمار بسازید و از ()setInterval استفاده می‌کنید باید راهی وجود داشته باشد که وقتی دیگر از این component در پروژه‌ی خود استفاده نمی‌کنیم بتوانیم جلوی اجرا شدن آن را با ()clearInterval بگیریم.

this.state = {
    stopWatch: 0
}

stopWatchHandler = () => {
    this.setState(prevState => {
        return {
            stopWatch: prevState.stopWatch + 1
        }
    });
}

componentDidMount() {
    setInterval(this.stopWatchHandler, 1000);
}

componentWillUnmount() {
    clearInterval(this.stopWatchHandler);
}


برای ساخت ثانیه شمار در مثال بالا ابتدا یک متغیر state با نام stopWatch و مقدار اولیه 0 در کامپوننت خود تعریف کرده‌ایم. سپس در متد stopWatchHandler یک واحد به مقدار stopWatch اضافه می‌کنیم. مرحله ی بعد در متد componentDidMount با استفاده از setInterval متد stopWatchHandler را هر یک ثانیه اجرا می‌کنیم و مقدار stopWatch را یک واحد افزایش می‌دهیم.

حالا فرض کنید که ثانیه شمار بخشی از پروژه شما است. که پس از استفاده دیگر به آن احتیاج ندارید اگر تابع setInterval را با استفاده از clearInterval غیرفعال نکنید این تابع هر یک ثانیه اجرا می‌شود و یک واحد به stopWatch اضافه می‌کند. این یعنی حتی وقتی که دیگر نیازی به ثانیه شمار در پروژه‌ی خود ندارید، ثانیه شمار همچنان در حال اجرا در پروژه‌ی شما است و از منابع استفاده می‌کند.

برای جلوگیری از این کار می‌توانید از متد componentWillUnmount استفاده کنید. این متد آخرین مرحله از چرخه‌ی حیات در ری‌اکت می‌باشد که در آن می توانید clearInterval را اجرا کرده و از اجرای ثانیه شمار در موقعی که به آن احتیاج ندارید جلوگیری کنید.


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