learnreact
learnreact
خواندن ۱۴ دقیقه·۴ سال پیش

State and Lifecycle in React js

در این صفحه مفهوم  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);

کد را در CodePen امتحان کنید.

در این بخش، ما یاد خواهیم گرفت که چگونه کامپوننت 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);

کد را در CodePen امتحان کنید.

با این حال، این  یک نیاز اساسی را از دست می دهد: این واقعیت که Clock یک تایمر تنظیم می کند و UI را در هر ثانیه به روز می کند ، باید جزئیات اجرای Clock باشد.

درحالت ایده آل می خواهیم یک بار بنویسید و خود Clock به روز رسانی را داشته باشد:

ReactDOM.render( <Clock />, document.getElementById('root') );

برای پیاده سازی این، باید “state” را به Clock component اضافه کنیم.

State شبیه به prop ها هستند، اما خصوصی (private) است و کاملا توسط آن کنترل می شود.

تبدیل یک فانکشنال کامپوننت  به کلاس کامپوننت | Converting a Function to a Class in react js

می توانید یک function component مانند Clock را در پنج مرحله به class component تبدیل کنید:

  1. یک کلاس ES6 با همان نام ایجاد کنید، که از Reqact.Component گسترش (extends) می دهد.
  2. یک متد ()render خالی اضافه کنید .
  3. بدنه function را به متد ()render منتقل کنید.
  4. Props ها را با this.props در بدنه ()render جایگزین کنید.
  5. باقی function مانده خالی را حذف کنید.
class Clock extends React.Component { render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.props.date.toLocaleTimeString()}.</h2> </div> ); } }

کد را در CodePen امتحان کنید.

حالا Clock را به عنوان یک class تعریف شده نه یک function

در هر بار که یک  بروز رسانی اتفاق می افتد متد render فرار خوانده می شود، اما تا زمانی که render کنیم <Clock /> با همان DOM node ، فقط یک نمونه از کلاس Clock استفاده خواهد شد.

این به ما امکان می دهد از ویژگی های اضافه مانند local state و lifecycle methods استفاده کنیم.

اضافه کردن Local State به کلاس کامپوننت | Adding Local State to a Class

ما date را از props به state در سه مرحله انتقال می دهیم:

  1. جایگزین this.props.date با this.state.date در متد ()render.
class Clock extends React.Component { render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div> ); } }
  1. به کلاس یک constructor اضافه کنید که this.state اولیه را اختصاص دهید:
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 در ارتباط باشد.

  1. Date را حذف prop از </Clock> المنت:
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') );

کد را در CodePen امتحان کنید.

در مرحله بعد، ما Clock  را تنظیم خواهیم کرد که هر ثانیه خود را به روز می کنیم.

اضافه کردن متدهای Lifecycle به یک کلاس کامپوننت | Adding Lifecycle Methods to a Class component

در برنامه ها بسیاری از 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 ها خوانده می شوند را دوباره یادآوری کنیم:

  1. وقتی < / Clock> به ()render منتقل شد، React کامپوننت سازنده Clock را فراخوانی می کند. از آنجا که Clock باید زمان فعلی را نشان دهد، این this.state را با یک object از جمله زمان فعلی آغاز می کند. بعداً این حالت را به روز خواهیم کرد.
  2. سپس React با متد ()render کامپوننت Clock ارتباط می گیرد. اینگونه است که React متوجه می شود چه باید روی صفحه نمایش داده شود. React سپس DOM بروز می کند تا مطابق با خروجی رندر Clock باشد.
  3. هنگامی که خروجی Clock در DOM درج می شود ، React از ()componentDidMount متد lifecycle  استفاده می کند.در داخل آن ، کامپوننت Clock از مرورگر می خواهد یک تایمر تنظیم کند تا یک بار در ثانیه با فراخوانی متد کامپوننت ()tick ارتباط برقرار کند.
  4. در هر ثانیه مرورگر از متد ()tick استفاده می کند. در داخل آن، Clock component با فراخوانی ()setState با یک object حاوی زمان فعلی، یک بروز رسانی UI را برنامه ریزی می کند. باتشکر از ارتباط با setState()، React می داند  که state تغییر کرده است و دوباره متد ()render را فرا می خواند تا متوجه شود چه چیزی باید روی صفحه باشد. این بار، this.state.date در متد ()render خواهد بود، بنابر این خروجی render شامل زمان بروز می شود. بنا بر این  React بروز رسانی می کند.
  5. اگر Clock component از DOM حذف شود، React را با استفاده از ()componentWillUnmount متد lifecycle فراخوانی می کند تا تایمر متوقف شود.

استفاده درست از Using State Correctly | State

سه مورد وجود دارد که باید درباره ()setState بدانید.

State را به طور مستقیم ویرایش نکنید | Do Not Modify State Directly

به عنوان مثال، این یک component را دوباره render نمی دهد:

// Wrong this.state.comment = 'Hello';

در عوض، از ()setState استفاده کنید:

// Correct this.setState({comment: 'Hello'});
تنها جای که می توانید ورودی اختصاص دهید به this.state در constructor است.

بروزسانی های State ممکن است ناهمزمان باشد | State Updates May Be Asynchronous

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 }; });

بروزرسانی های State ترکیب می شوند  | State Updates are Merged

وقتی با ()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 است.

داده ها پایین می رود | The Data Flows Down

هیچکدام از 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 به زبان فارسی قراردادیم خوشحال میشیم به سایت سر بزنی و نظرت رو بگی:)

statereactreact jsآموزش reactآموزش react js به فارسی
ما ترجمه مستندات React js رو به زبان فارسی میذاریم تا شما به راحتی یاد بگیرید و پیشرفت کنید.خوشحال میشیم بعد خوندن مطالب ما نظرت رو به ما بگی:) learnreactapp.com
شاید از این پست‌ها خوشتان بیاید