در این صفحه مفهوم state و lifecycle در یک component React معرفی می شود.
مثال ساعت را از بخش های قبلی درنظر بگیرید. در Rendering Elements، ما فقط یک راه برای بروز رسانی UI آموختیم. ما برای تغییر در خروجی رندر شده با ()ReactDOM.render ارتباط می گیریم :
function tick() {
const element = (
<div>
<h1>Hello, world!</h1>
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(
element,
document.getElementById('root')
);
}
setInterval(tick, 1000);
در این بخش، ما یاد خواهیم گرفت که چگونه کامپوننت Clock را واقعا قابل استفاده مجدد و محصور کنیم. تایمر خود را تنظیم می کند و هر ثانیه خود را بروز می کند.
ما می توانیم از این که چگونه ساعت به نظر می رسد شروع کنیم:
function Clock(props) { return ( <div> <h1>Hello, world!</h1> <h2>It is {props.date.toLocaleTimeString()}.</h2> </div> ); } function tick() { ReactDOM.render( <Clock date={new Date()} />, document.getElementById('root') ); } setInterval(tick, 1000);
با این حال، این یک نیاز اساسی را از دست می دهد: این واقعیت که Clock یک تایمر تنظیم می کند و UI را در هر ثانیه به روز می کند ، باید جزئیات اجرای Clock باشد.
درحالت ایده آل می خواهیم یک بار بنویسید و خود Clock به روز رسانی را داشته باشد:
ReactDOM.render( <Clock />, document.getElementById('root') );
برای پیاده سازی این، باید “state” را به Clock component اضافه کنیم.
State شبیه به prop ها هستند، اما خصوصی (private) است و کاملا توسط آن کنترل می شود.
می توانید یک function component مانند Clock را در پنج مرحله به class component تبدیل کنید:
class Clock extends React.Component { render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.props.date.toLocaleTimeString()}.</h2> </div> ); } }
حالا Clock را به عنوان یک class تعریف شده نه یک function
در هر بار که یک بروز رسانی اتفاق می افتد متد render فرار خوانده می شود، اما تا زمانی که render کنیم <Clock /> با همان DOM node ، فقط یک نمونه از کلاس Clock استفاده خواهد شد.
این به ما امکان می دهد از ویژگی های اضافه مانند local state و lifecycle methods استفاده کنیم.
ما date را از props به state در سه مرحله انتقال می دهیم:
class Clock extends React.Component { render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div> ); } }
class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div> ); } }
توجه کنید که چگونه props را به constructor می دهیم:
constructor(props) { super(props); this.state = {date: new Date()}; }
Class component ها همیشه باید با constructor و props در ارتباط باشد.
ReactDOM.render( <Clock />, document.getElementById('root') );
بعدا کد تایمر را به خود component اضافه خواهیم کرد.
نتیجه به نظر می رسد:
class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div> ); } } ReactDOM.render( <Clock />, document.getElementById('root') );
در مرحله بعد، ما Clock را تنظیم خواهیم کرد که هر ثانیه خود را به روز می کنیم.
در برنامه ها بسیاری از component ها، آزاد کردن منابع که توسط component ها هنگام حذف شدن گرفته می شود بسیار مهم است.
هروقت که Clock برای بار اولین بار در DOM رندر می شود می خواهیم یک تایمر تنظیم کنیم. در react به “mounting” گفته می شود.
ما همچنین می خواهیم هر زمان که DOM تولید شده توسط Clock براشته شد، این تایمر را پاک کنیم. در React این را “unmounting” گفته می شود.
ما می توانیم متدهای ویژه ای را درclass component برای اجرای برخی کدها هنگام mounts و unmounts در کامپوننت اجرا کنیم :
class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } componentDidMount() { } componentWillUnmount() { } render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div> ); } }
این متدها “lifecycle methods” نامیده می شوند.
متد ()componentDidMount بعد از رندر خروجی component در DOM اجرار می شود. این مکان مناسب برای تنظیم تایمر است :
componentDidMount() { this.timerID = setInterval( () => this.tick(), ۱۰۰۰ ); }
توجه کنید که چگونه timer ID را درست در this مورد ذخیره می کنیم (this.timerID) .
درحالی که this.props توسط خود React تنظیم شده اند و this.state معنای خواصی دارد، اگر نیاز به ذخیره چیزی دارید که در جریان داده ها مشارکت نداشته باشد (مانند شناسه تایمر) می توانید زمینه های (fields) اضافی را به صورت دستی به کلاس اضافه کنید.
ما تایمر را به ()componentWillUnmount متدی از lifecycle ترکیب می کنیم:
componentWillUnmount() { clearInterval(this.timerID); }
سرانجام، ما متد ()tick را اجرا خواهیم کرد که کامپوننت Clock هر ثانیه اجرا می شود.
از ()this.setState برای برنامه ریزی بروز رسانی های local state کامپوننت استفاده خواهیم کرد:
class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } componentDidMount() { this.timerID = setInterval( () => this.tick(), ۱۰۰۰ ); } componentWillUnmount() { clearInterval(this.timerID); } tick() { this.setState({ date: new Date() }); } render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div> ); } } ReactDOM.render( <Clock />, document.getElementById('root') );
این کد را در CodePen امتحان کنید.
حالا هر ثاینه ساعت تیک تاک می کند.
بیایید سریعاً آنچه را که اتفاق می افتد و نظمی که methods ها خوانده می شوند را دوباره یادآوری کنیم:
سه مورد وجود دارد که باید درباره ()setState بدانید.
به عنوان مثال، این یک component را دوباره render نمی دهد:
// Wrong this.state.comment = 'Hello';
در عوض، از ()setState استفاده کنید:
// Correct this.setState({comment: 'Hello'});
React ممکن است چندین فراخوانی ()setState برای عملکرد بروز کند.
چون this.Props و this.state ممکن است به صورت غیر همزمان بروز شود، برای محاسبات بعدی نباید به مقادیر آنها عتماد کنید.
به عنوان مثال، این کد ممکن است در بروز رسانی counter به مشکل بربخورد :
// Wrong this.setState({ counter: this.state.counter + this.props.increment, });
برای رفع آن، از فرم دوم ()setState استفاده کنید که یک function را به جای object می پذیرد. این function حالت قبلی (previous state ) را به عنوان اولین argument در یافت می کند، و props ها در زمان بروز رسانی به عنوان argument دوم اعمال می شود :
// Correct this.setState((state, props) => ({ counter: state.counter + props.increment }));
ما از arrow function در بالا استفاده کردیم، اما با function های معمولی نیز کار می کند:
// Correct this.setState(function(state, props) { return { counter: state.counter + props.increment }; });
وقتی با ()setState ارتباط می گیرید، React آبجکتی را که در state فعلی ارائه می دهد ادغام می شود.
به عنوان مثال، state شما ممکن است شامل چندین variables مستقل باشد:
constructor(props) { super(props); this.state = { posts: [], comments: [] }; }
سپس می توانید با ارتباط های جداگانه ()setState آنها را به صورت جدا بروز کنید :
componentDidMount() { fetchPosts().then(response => { this.setState({ posts: response.posts }); }); fetchComments().then(response => { this.setState({ comments: response.comments }); }); }
ادغام کم عمق است ، بنابراین ({this.setState({comments برگها this.state.posts دست نخورده، اما کاملاً جایگزین this.state.comments است.
هیچکدام از component های parent و child نمی تواند بدانند که آیا component خاصی دارای حالت ویا بدون stateless است، و نباید اهمیت دهند که آیا به عنوان یک function یا یک class تعریف شده است.
به همین دلیل است که state معمولا محلی یا محصور نامیده می شود. در دسترس هیچ component غیر از component نیست که آن را در اختیار داشته باشد و آن را تنظیم کند.
در یک component ممکن است که state خود را به عنوان props به child خود منتقل کند:
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
همچنین برای components های تعریف شده توسط کاربر کار می کند:
<FormattedDate date={this.state.date} />
کامپوننت FormattedDate تاریخ را در props دریافت می کند و نمی داند که آیا آن از نظر state Clock’s آمده است، از Clock’s props با دست تایپ شد:
function FormattedDate(props) { return <h2>It is {props.date.toLocaleTimeString()}.</h2>; }
این کد را در CodePen امتحان کنید.
این معمولا یک جریان داده “از بالا به پایین” (top-down ) یا “یک طرفه” ( unidirectional ) نامیده می شود. هر state همیشه متعلق به یک component خا ص است، و هر داده یا UI حاصل از آن می تواند بر state “زیر” ( below ) درخت تاثیر بگذارد.
اگر یک component را به عنوان یک درخت و props را به عنوان یک آبشار کنید، state هر component’s مانند یک آب اضافی است که در یک نقطه دلخواه به آن می پیوندد، بلکه به پایین جریان می یابد.
برای نشان دادن اینکه همه component ها واقعاً جدا هستند ، ما می توانیم یک App component ایجاد کنیم که سه <Clock> را ارائه می دهد:
function App() { return ( <div> <Clock /> <Clock /> <Clock /> </div> ); } ReactDOM.render( <App />, document.getElementById('root') );
این کد را در CodePen امتحان کنید.
هر Clock تایمر خود را تنظیم می کند و به طور مستقل به روز می شود.
در برنامه های React ، این که آیا یک component حالت پذیر یا بی تابعیت است (stateful or stateless ) ، جزئیات اجرای component است که ممکن است با گذشت زمان تغییر کند. می توانید از components بدون تابش (stateless ) در داخل components های حالت پذیر (stateful ) استفاده کنید ، و برعکس.
ما در سایتمون آموزش React js به زبان فارسی قراردادیم خوشحال میشیم به سایت سر بزنی و نظرت رو بگی:)