State and Lifecycle- 1

مثال ساعت را در مطالب قبل در نظر بگیرید. با render کردن المنت ها فقط یک روش برای آپدیت کردن UI داشتیم. با فراخوانی ReactDOM.render() خروجی render شده را تغییر میدادیم. function tick(){const element = (<div>{new Date().toLocaleTimeString()}</div>);ReactDOM.render(element,document.getElementById('root'));}setInterval(tick, 1000);حالا میخواهیم کامپوننت Clock را به صورت reusable و encapsulated ایجاد کنیم. به طوری که تایمر خودش را داشته باشد و هر ثانیه خودش را آپدیت کند.ابتدا نحوه نمایش را از کل تابع tick جدا میکنیم:function Clock(props){ return (<div>{props.date.toLocaleTimeString()}</div>);}function tick(){ ReactDOM.render(<Clock date={new Date()} />,document.getElementById('root'));}setInterval(tick, 1000);اما میخواهیم که در خود Clock تایمر را تنظیم و UI را آپدیت کنیم. یعنی میخواهیم کد زیر را یک بار بنویسیم و Clock خودش را آپدیت کند:ReactDOM.render(<Clock />, document.getElementById('root'));برای این کار باید به کامپوننت Clock مان state اضافه کنیم. state مثل props است ولی خصوصی است و توسط کامپوننت کنترل میشود. قبلا گفته بودیم که کامپوننت هایی که با class تعریف میشوند ویژگی بیشتری دارند، این ویژگی state است. تبدیل تابع به کلاس یک ES6 class با همان نام ایجاد میکنیم که از React.Component استخراج میشود.یک متد خالی render() به آن اضافه میکنیم.بدنه تابع را داخل متد render() میگذاریم.در بدنه render() به جای props از this.props استفاده میکنیم.class Clock extends React.Component { render() { return (<div>{this.props.date.toLocaleTimeString()}</div>); }} متد render هر بار که آپدیتی رخ دهد فراخوانی میشود، اما تا زمانی که <Clock /> را در همان DOM node م render کنیم، فقط یک نمونه از کلاس Clock استفاده میشود. این به ما امکان میدهد از ویژگی های اضافی مثل local state و متدهای lifecycle استفاده کنیم.اضافه کردن local state به یک کلاس در سه مرحله date را از props به state منتقل میکنیم: در متد render() عبارت this.props.date را با this.state.date جایگزین میکنیم.یک class constructor که مقدار اولیه this.state را تعیین میکند اضافه میکنیم. دقت کنید که چگونه props را به constructor مان pass میکنیم. کامپوننت های تعریف شده با class باید همیشه constructor را با props فراخوانی کنند.م date prop را از المنت <Clock /> در ReactDOM.render() حذف میکنیم. بعدا کد تایمر را در خود کامپوننت اضافه میکنیم. class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } render() {return (<div>{this.state.date.toLocaleTimeString()}</div>); }}ReactDOM.render(<Clock />, document.getElementById('root'));حالا میخواهیم Clock خودش تایمر خودش را تنظیم کند و هر ثانیه آپدیت شود.اضافه کردن متدهای lifecycle به یک کلاسدر اپلیکیشن هایی که از کامپوننت های زیادی استفاده میکنند، خیلی مهم است که منابعی که اشغال کرده اند، بعد از از بین رفتنشان آزاد شود.میخواهیم هر موقع که Clock در DOM برای اولین بار render میشود یک تایمر تنظیم کنیم. در React به این کار mounting میگویند. همچنین میخواهیم هر موقع که DOM ایجاد شده توسط Clock حذف میشود، آن تایمر را پاک کنیم. در React به این کار unmounting میگویند. میتوانیم موقع mount و unmount شدن کامپوننت، متدهای خاصی را در کلاس کامپوننت declare کنیم: componentDidMount() و componentWillUnmount(). این ها متدهای lifecycle نام دارند.متد componentDidMount() بعد از اینکه خروجی کامپوننت در DOM م render شد اجرا میشود. اینجا جای مناسبی برای تنظیم تایمر است. توجه کنید که چگونه timerID در this ذخیره میشود:componentDidMount(){this.timerID = setInterval( ()=>this.tick(), 1000 );}چون this.props توسط خود React تنظیم میشود و this.state معنی خاص خودش را دارد، اگر نیاز باشد چیزی را ذخیره کنیم که در data flow مشارکتی ندارد (مثل timerID)، میتوانیم خودمان فیلدهای دیگری به کلاس اضافه کنیم.تایمر را در متد componentWillUnmount() از بین میبریم:componentWillUnmout(){clearInerval(this.timerID);}در نهایت، متد tick() را پیاده سازی میکنیم تا کامپوننت Clock هر ثانیه اجرا شود. در آن از this.setState() استفاده میشود تا آپدیت های local state را زمانبندی کند:tick(){this.setState({ date: new Date() });}اتفاقاتی که می افتد را به ترتیب مرور میکنیم:زمانی که <Clock /> به ReactDOM.render() م pass میشود، React م constructor کامپوننت Clock را فراخوانی میکند. چون Clock باید زمان الان را نشان دهد، this.state را با شیئی که زمان حال را نشان میدهد مقداردهی اولیه میشود. بعدا این state را آپدیت میکنیم.سپس React متد render() از کامپوننت Clock را فراخوانی میکند. به این صورت React میفهمد که چه چیزی را در صفحه نمایش دهد. سپس React م DOM را آپدیت میکند تا با خروجی render از Clock مطابقت داشته باشد.زمانی که خروجی Clock در DOM وارد شد، React متد componentDidMount() را فراخوانی میکند. در آن، کامپوننت Clock از بروزر میخواهد تایمری تنظیم کند تا هر ثانیه یک بار متد tick کامپوننت را فراخوانی کند.هر ثانیه بروزر متد tick() را فراخوانی میکند. در متد tick کامپوننت Clock با فراخوانی setState() با یک شیء شامل زمان حال، UI را آپدیت میکند. React با متد setState() میداند که state تغییر کرده است و دوباره متد render() را فراخوانی میکند تا بفهمد چه چیزی باید در صفحه نمایش داده شود. این بار this.state.date در متد render() متفاوت است، بنابراین خروجی render شامل زمان آپدیت شده است. بر این اساس React م DOM را آپدیت میکند.اگر کامپوننت Clock زمانی از DOM حذف شود، React متد componentWillUnmout را فراخوانی میکند و تایمر متوقف میشود.class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } componentDidMount() { this.timerID = setInterval( () => this.tick(), 1000); } componentWillUnmount() { clearInterval(this.timerID); } tick() { this.setState({date: new Date()}); } render() { return (<div>It is {this.state.date.toLocaleTimeString()}</div>); }}ReactDOM.render(<Clock />, document.getElementById('root'));