در این درس به چند تا از رایج ترین توابع چرخه حیات که می توانیم در کامپوننت های ری اکت از آن استفاده کنیم، می پردازیم و دلیل اهمیت انها و نحوه استفاده از هرکدام از این توابع را آموزش خواهیم داد.
در روز گذشته درباره کامپوننت های stateful صحبت کردیم و یاد گرفتیم که چطور این کامپوننت ها وضعیت درونی خودشان را نگهداری می کنند. در درس امروز قصد داریم کمی درباره نحوه کارکرد یک کامپوننت در یک اپلیکیشن صحبت کنیم.
درس امروز راجع به چرخه حیات (Lifecycle) کامپوننت ها است.
فریم ورک ری اکت تعدادی متد به ما می دهد تا توسط آن بتوانیم درهر زمان از چرخه حیات کامپوننت که خواستیم، قابلیت هایی را اضافه کنیم. به اولین متد چرخه حیات که در زیر آمده توجه کنید.
هنگامی که یک کامپوننت روی یک صفحه برنامه مان تعریف می شود، نمی توانیم بلافاصله به عنصرهای DOM آن دسترسی داشته باشیم، چون ما گره (عنصر)های مجازی تعریف کردیم.
بنابراین باید تا زمانی که کامپوننت خودش را بطور کامل در مرورگر قرار دهد (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 نیست و به همین شکلی که هست، کار خواهد کرد.
گاهی اوقات می خواهیم بعضی از داده های کامپوننت مان را قبل یا بعد از رندر شدن کامپوننت، بروزرسانی کنیم. برای مثال فرض کنید می خواهیم یک تابع برای زمانی که کامپوننت درحال رندر شدن است و یا یک تابع برای موقعی که props یک کامپوننت تغییر کرد، فراخوانی کنیم.
متد componentWillUpdate
برای مدیریت تغییرات یک کامپوننت، استفاده می شود (به شرطی که از this.setState
برای مدیریت تغییرات استفاده نکنیم، چون در اینصورت یک حلقه بی نهایت در برنامه بوجود خواهد آمد).
یکی دیگر از متدهای چرخه حیات، متد 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> ); } }
در اینجا یک عنصر جدید داریم که فرزندان یک عنصر را نمایش می دهند. این الگویی است که به ما اجازه می دهد تا یک کلاس 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 قرار گرفته، استفاده می کند و هنگامی که رفرشی انجام می شود، بطور تصادفی چهار عنصر را از آن بر می داریم، با این کار در حقیقت یک رفرش را شبیه سازی کرده ایم.
قبل از اینکه یک کامپوننت از حالت 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های یک کامپوننت تعریف و مستندسازی کرد تا هنگامی که قصد اشتراک گذاری آن کامپوننت با تیم ها و یا یک برنامه دیگر را داشته باشید، بتوانید اینکار را انجام دهید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.