React تماماً در مورد ساخت رابط کاربری است. و برای انجام این کار به طور موثر، React راه هایی را برای کامپوننت ها فراهم می کند تا چرخه عمر خود را مدیریت کنند.
این بدان معناست که کامپوننت ها می توانند وظایف خاصی را در مراحل مختلف وجود خود انجام دهند، از لحظه ای که ایجاد می شوند تا زمانی که از رابط کاربری حذف می شوند.
روشهای چرخه حیات برای سالها بخش اساسی React بودهاند. اما با معرفی هوکها، رویکرد React برای مدیریت state ها و side effects در کامپوننت های توابعی بصریتر و انعطافپذیرتر شده است.
فقط یک نکته سریع: اگرچه هوک ها به طور کلی جایگزین کامپوننت کلاس می شوند، اما هیچ برنامه ای برای حذف کلاس ها از React وجود ندارد.
چرا این مقاله؟
در این آموزش با متدهای چرخه حیات کامپوننت کلاس مانند componentDidMount
، componentDidUpdate
، componentWillUnmount
و shouldComponentUpdate
آشنا می شوید.
همچنین هوک های React مانند useState
، useEffect
و useContext
را کاوش خواهید کرد و دلیل معرفی آنها را درک خواهید کرد. این کار سفر React شما را روانتر و لذت بخش تر می کند.
چه تازه کار با React را شروع کرده باشید یا به دنبال تعمیق درک خود باشید، این راهنما شما را با دانشی که برای ساختن برنامه های وب واکنشگرا و تعاملی با استفاده از ابزارهای قدرتمند React نیاز دارید، مجهز می کند.
Lifecycle کامپوننت چگونه کار می کند؟
در React، کامپوننت ها یک چرخه حیات متشکل از مراحل مجزا را طی می کنند. هر یک از این مراحل روشهای خاصی را ارائه میدهد که میتوانید آنها را برای اجرای کد در لحظات مختلف در طول وجود یک کامپوننت سفارشی کنید.
این روشها به شما کمک میکنند تا کارهایی مانند مقداردهی اولیه دادهها، مدیریت بهروزرسانیها و مرتب کردن منابع را در صورت نیاز انجام دهید.
متدهای چرخه حیات کامپوننت های کلاس
بیایید با نگاهی به متدهای چرخه حیات کامپوننت کلاس شروع کنیم. اینها راه اصلی مدیریت چرخه عمر کامپوننت قبل از معرفی هوک ها بودند.
نحوه استفاده از componentDidMount
:
این پس از درج(قرار گرفتن) یک کامپوننت در DOM فراخوانی می شود. این یک مکان عالی برای انجام وظایف راهاندازی اولیه، مانند واکشی دادهها از یک API یا راهاندازی event listeners است.
مثال کد:
import React, { Component } from 'react';
class MyComponent extends React.Component {
constructor() {
super();
this.state = {
data: null,
};
}
componentDidMount() {
// This is where you can perform initial setup.
// In this example, we simulate fetching data from an API after the component has mounted.
// We use a setTimeout to mimic an asynchronous operation.
setTimeout(() => {
const fetchedData = 'This data was fetched after mounting.';
this.setState({ data: fetchedData });
}, 2000); // Simulate a 2-second delay
}
render() {
return (
<div>
<h1>componentDidMount Example</h1>
{this.state.data ? (
<p>Data: {this.state.data}</p>
) : (
<p>Loading data...</p>
)}
</div>
);
}
}
export default MyComponent;
در این مثال، ما یک کامپوننت کلاس به نام MyComponent
ایجاد کردیم. در سازنده، state کامپوننت با مجموعه داده ها به null مقداردهی اولیه می شود و ما از آن برای ذخیره داده های واکشی شده استفاده می کنیم.
در متد componentDidMount
، ما واکشی دادهها از یک API را با استفاده از setTimeout
شبیهسازی میکنیم تا یک عملیات ناهمزمان را تقلید کنیم. پس از 2 ثانیه (2000 میلی ثانیه)، state کامپوننت با داده های واکشی شده به روز می شود.
در متد رندر، محتوا به صورت مشروط بر اساس state داده ارائه می شود. اگر داده ها null باشند، یک پیام ...Loading data
نمایش داده می شود. در غیر این صورت، داده های واکشی شده نمایش داده می شود.
هنگامی که از این کامپوننت در برنامه خود استفاده می کنید، متوجه خواهید شد که ابتدا پیام ...Loading data
نمایش داده می شود و پس از 2 ثانیه، داده های واکشی شده نمایش داده می شود. این نشان می دهد که چگونه componentDidMount
برای انجام وظایف پس از اضافه شدن یک کامپوننت به DOM مفید است.
نحوه استفاده از componentDidUpdate
:
این پس از رندر شدن مجدد کامپوننت به دلیل تغییر در state یا پروپ های آن نامیده می شود. این یک مکان عالی برای رسیدگی به side effect یا انجام اقدامات اضافی بر اساس آن تغییرات است.
مثال کد:
import React, { Component } from 'react';
class Counter extends React.Component {
constructor() {
super();
this.state = {
count: 0,
};
}
// This method will be called when the "Increment" button is clicked
handleIncrement = () => {
this.setState({ count: this.state.count + 1 });
};
// componentDidUpdate is called after the component updates
componentDidUpdate(prevProps, prevState) {
// You can access the previous props and state here
console.log('Component updated');
console.log('Previous state:', prevState);
console.log('Current state:', this.state);
}
render() {
return (
<div>
<h1>Counter</h1>
<p>Count: {this.state.count}</p>
<button onClick={this.handleIncrement}>Increment</button>
</div>
);
}
}
export default Counter;
در این مثال کد، ما یک کامپوننت کلاس Counter
با سازنده ای ایجاد می کنیم که حالت شمارش را به 0 مقداردهی اولیه می کند. متد handleIncrement
با کلیک روی دکمه Increment
، استیت شمارش را به روز می کند.
در متد چرخه حیات componentDidUpdate
، ما یک پیام (Component updated
) را به کنسول وارد می کنیم. ما همچنین هر دو state قبلی (prevState
) و state
فعلی (this.state
) را ثبت می کنیم. این نشان می دهد که چگونه می توانید به مقادیر قبلی و فعلی در طول یک به روز رسانی دسترسی داشته باشید. روش رندر تعداد فعلی و دکمه ای برای افزایش آن را نمایش می دهد.
اکنون، هنگامی که از این کامپوننت Counter
در برنامه خود استفاده می کنید، کنسول مرورگر را باز کنید. هر بار که روی دکمه Increment
کلیک می کنید، پیام هایی را در کنسول مشاهده خواهید کرد که نشان می دهد کامپوننت به روز شده است، همراه با مقادیر state قبلی و فعلی.
میتوانید از componentDidUpdate
برای اهداف مختلفی استفاده کنید، مانند درخواستهای شبکه در هنگام تغییر state یا پروپوزال، بهروزرسانی DOM بر اساس تغییرات state، یا تعامل با کتابخانههای شخص ثالث پس از بهروزرسانی. این متدی برای انجام اقداماتی ارائه می دهد که باید به طور خاص پس از رندر شدن مجدد یک کامپوننت انجام شوند.
نحوه استفاده از componentWillUnmount
:
این درست قبل از حذف یک کامپوننت از DOM فراخوانی می شود. این مکان بسیار مهمی برای انجام کارهای پاکسازی، مانند پاک کردن تایمرها، لغو اشتراک از رویدادها، یا انتشار منابع برای جلوگیری از نشت حافظه است.
بیایید یک کامپوننت ساده React را نشان دهیم که با استفاده از متد componentDidMount
تایمر را هنگام نصب تنظیم میکند، و زمانی که با استفاده از متد componentWillUnmount
آن تایمر را جدا میکند، آن را پاک میکند.
مثال کد:
import React, { Component } from 'react';
class TimerComponent extends React.Component {
constructor() {
super();
this.state = {
seconds: 0,
};
this.timer = null; // Initialize the timer
}
// When the component mounts, start the timer
componentDidMount() {
this.timer = setInterval(() => {
this.setState({ seconds: this.state.seconds + 1 });
}, 1000); // Update every 1 second (1000 milliseconds)
}
// When the component unmounts, clear the timer to prevent memory leaks
componentWillUnmount() {
clearInterval(this.timer);
}
render() {
return (
<div>
<h1>Timer Component</h1>
<p>Elapsed Time: {this.state.seconds} seconds</p>
</div>
);
}
}
export default TimerComponent;
در این مثال کلاس TimerComponent
را ایجاد کردیم. در داخل سازنده، state کامپوننت با خاصیت seconds مقداردهی اولیه می شود، که ما از آن برای پیگیری زمان سپری شده استفاده می کنیم. متغیر تایمر نیز روی null تنظیم شده است.
در متد چرخه زندگی componentDidMount
، تایمر با استفاده از setInterval
شروع می شود. این تایمر هر ثانیه خاصیت استیت ثانیه را افزایش می دهد.
در متد چرخه زندگی componentWillUnmount
، تایمر با استفاده از clearInterval
پاک میشود تا اطمینان حاصل شود که پس از حذف کامپوننت از DOM به کار خود ادامه نمیدهد.
در متد رندر زمان سپری شده بر اساس پروپرتی state seconds نمایش داده می شود.
هنگامی که از این TimerComponent
در برنامه خود استفاده می کنید و آن را رندر می کنید، متوجه خواهید شد که تایمر زمانی که کامپوننت نصب می شود شروع می شود و زمانی که کامپوننت خارج می شود متوقف می شود. این به لطف پاکسازی انجام شده در متد componentWillUnmount
است. این از نشت منابع جلوگیری می کند و آن را تضمین می کند
تایمر در طول چرخه عمر قطعه به درستی مدیریت می شود.
نحوه استفاده از shouldComponentUpdate
:
ما از این متد چرخه عمر استفاده می کنیم تا کنترل کنیم که آیا یک کامپوننت باید زمانی که state یا پروپ های آن تغییر می کند دوباره رندر شود یا خیر. به ویژه برای بهینه سازی عملکرد با جلوگیری از رندرهای غیر ضروری مفید است.
بیایید یک کامپوننت کلاس React ساده بسازیم و از متد shouldComponentUpdate
استفاده کنیم تا تصمیم بگیریم که آیا کامپوننت باید بر اساس تغییرات در stateش دوباره رندر شود یا خیر.
مثال کد:
import React, { Component } from 'react';
class Counter extends React.Component {
constructor() {
super();
this.state = {
count: 0,
};
}
shouldComponentUpdate(nextProps, nextState) {
// Allow the component to re-render only if the count is even
if (nextState.count % 2 === 0) {
return true; // Re-render
}
return false; // Don't re-render
}
incrementCount = () => {
this.setState((prevState) => ({ count: prevState.count + 1 }));
};
render() {
return (
<div>
<h1>Counter Example</h1>
<p>Count: {this.state.count}</p>
<button onClick={this.incrementCount}>Increment</button>
</div>
);
}
}
export default Counter;
در این مثال، ما کامپوننت کلاس Counter
را ایجاد کردیم که یک stet شمارش را حفظ می کند، که از 0 شروع می شود. در متد shouldComponentUpdate
، بررسی می کنیم که آیا تعداد حالت بعدی زوج است یا خیر. اگر اینطور است، اجازه می دهیم کامپوننت دوباره رندر شود. در غیر این صورت از رندر مجدد جلوگیری می کنیم.
متد incrementCount
زمانی فراخوانی می شود که دکمه Increment کلیک شود. این stete شمارش را با افزایش آن به روز می کند.
در متد رندر، شمارش جاری و دکمه ای برای افزایش آن نمایش داده می شود.
اگر روی دکمه Increment کلیک کنید و شمارش به یک عدد فرد تبدیل شود، کامپوننت دوباره رندر نمیشود. این رفتار نشان میدهد که چگونه میتوان از ComponentUpdate
برای بهینهسازی رندر در موقعیتهایی استفاده کرد که همه تغییرات حالت نباید باعث ایجاد رندر مجدد شوند.
معرفی React Hooks
React هوک های معرفی شده در نسخه 16.8. آنها به کامپوننت تابعی دسترسی به state و ویژگی های مختلف React را بدون نوشتن کامپوننت های کلاسی اعطا کردند.
در نتیجه، کامپوننتی کلاس تا حد زیادی غیر ضروری شده اند. هوک ها منطق کامپوننت را سادهتر میکنند و آن را قابل استفادهتر میکنند.
چرا از Hooks استفاده کنیم؟
هوک ها برای رفع چندین مشکل و درک و نگهداری کد React معرفی شدند:
پیچیدگی - هنگام مدیریت state و side effect، کامپوننتی کلاس می توانند پیچیده شوند.
قابلیت استفاده مجدد – منطق در کامپوننتی کلاس به راحتی بین کامپوننت قابل اشتراک گذاری نیست.
منحنی یادگیری - کامپوننتی کلاس منحنی یادگیری تندتری را برای تازه واردان به React معرفی می کنند.
React Hooks معمولا مورد استفاده قرار می گیرد
هوک useState
:
useState
به شما امکان می دهد state را به کامپوننت تابعی اضافه کنید. آرایه ای را با مقدار state فعلی و تابعی برای به روز رسانی آن برمی گرداند.
مثال کد:
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
در این مثال، ما از هوک useState
برای مدیریت state یک شمارنده استفاده کردیم. وقتی دکمه Increment
کلیک میشود، setCount state شمارش را بهروزرسانی میکند و باعث میشود که کامپوننت با مقدار بهروزرسانیشده دوباره رندر شود.
هوک useEffect
:
useEffect برای side effect در کامپوننت های تابعی، مشابه componentDidMount
و componentDidUpdate
استفاده می شود. پس از رندر اجرا می شود و با تعیین وابستگی ها قابل کنترل است.
مثال کد:
import React, { useState, useEffect } from 'react';
function Example() {
const [data, setData] = useState(null);
useEffect(() => {
// Fetch data from an API
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => setData(data));
}, []); // Empty dependency array, runs only once
return <div>{data ? data.message : 'Loading...'}</div>;
}
در این مثال، useEffect
برای واکشی دادهها از یک API هنگام نصب کامپوننت استفاده میشود. آرایه وابستگی خالی []
تضمین می کند که افکت فقط یک بار اجرا می شود.
هنگامی که دادهها واکشی میشوند، setData state دادهها را بهروزرسانی میکند و باعث میشود که اطلاعات واکشی شده دوباره ارائه شود.
هوک useContext
:
useContext
به کامپوننتی تابعی اجازه می دهد تا به مقادیر زمینه دسترسی داشته باشند. این روشی است برای انتقال داده به درخت کامپوننت بدون ارسال صریح props.
مثال کد:
import React, { useContext } from 'react';
// Create a context
const MyContext = React.createContext();
function MyComponent() {
const value = useContext(MyContext);
return <div>Context Value: {value}</div>;
}
در این مثال، کانتکستی به نام MyContext
ایجاد می کنیم. هوک useContext
به MyComponent
اجازه می دهد تا به مقدار ذخیره شده در این زمینه دسترسی داشته باشد. این یک ابزار قدرتمند برای مدیریت state گلوبال در برنامه شما است.
مزایای هوک های سفارشی
هوک های سفارشی توابعی هستند که از هوک ها به صورت داخلی استفاده می کنند و می توانند در چندین کامپوننت مجدداً استفاده شوند. آنها به محصور کردن و به اشتراک گذاشتن منطق پیچیده کمک می کنند.
در اینجا نمونه ای از یک هوک سفارشی به نام useLocalStorage
آورده شده است که ذخیره و بازیابی داده ها را در حافظه محلی مرورگر ساده می کند:
import { useState } from 'react';
function useLocalStorage(key, initialValue) {
// Retrieve the stored value from local storage
const storedValue = localStorage.getItem(key);
// Initialize the state with the stored value or the initial value
const [value, setValue] = useState(storedValue || initialValue);
// Update the local storage whenever the state changes
const setStoredValue = (newValue) => {
setValue(newValue);
localStorage.setItem(key, newValue);
};
return [value, setStoredValue];
}
export default useLocalStorage;
در این هوک سفارشی، useState
را از React وارد می کنیم زیرا از آن برای مدیریت استیت استفاده می کنیم. تابع useLocalStorage
دو پارامتر دارد:
key: رشته ای که نشان دهنده کلیدی است که داده ها تحت آن در حافظه محلی ذخیره می شوند.
initialValue: مقدار اولیه برای استیت.
در داخل هوک، ابتدا سعی کردیم با استفاده از localStorage.getItem(key)
مقدار ذخیره شده را از حافظه محلی بازیابی کنیم. سپس مقدار متغیر state را با استفاده از useState
مقداردهی اولیه کردیم، در صورت وجود از storedValue
یا در غیر اینصورت از initialValue
استفاده می کنیم.
در مرحله بعد، ما یک تابع setStoredValue
را تعریف کردیم که هنگام فراخوانی، state و حافظه محلی را به روز می کند. این مقدار جدید را در حافظه محلی با استفاده از localStorage.setItem (key، newValue)
تنظیم می کند.
در نهایت، یک آرایه [value، setStoredValue]
را به عنوان مقدار بازگشتی هوک برگرداندیم، که به کامپوننت اجازه می دهد به مقدار ذخیره شده دسترسی داشته باشند و در صورت نیاز آن را به روز کنند.
در اینجا مثالی از نحوه استفاده از هوک useLocalStorage
در یک کامپوننت آورده شده است:
import React from 'react';
import useLocalStorage from './useLocalStorage'; // Import the custom hook
function App() {
// Use the custom hook to manage a "username" stored in local storage
const [username, setUsername] = useLocalStorage('username', 'Guest');
const handleInputChange = (e) => {
setUsername(e.target.value);
};
return (
<div>
<h1>Hello, {username}!</h1>
<input
type="text"
placeholder="Enter your username"
value={username}
onChange={handleInputChange}
/>
</div>
);
}
export default App;
در این مثال، ما هوک سفارشی useLocalStorage
را وارد کرده و از آن برای مدیریت مقدار نام کاربری در حافظه محلی استفاده می کنیم. کامپوننت state نام کاربری را با استفاده از هوک مقداردهی اولیه می کند و زمانی که فیلد ورودی تغییر می کند آن را به روز می کند.
مقدار ذخیره شده و از فضای ذخیره سازی محلی بازیابی می شود و به آن اجازه می دهد در بارگذاری مجدد صفحه باقی بماند.
هوک های سفارشی روشی قدرتمند برای کپسولهسازی و استفاده مجدد از منطق پیچیده در برنامههای React هستند که کد شما را ماژولارتر و قابل نگهداریتر میکنند.
نتیجه
React ابزارهای قدرتمندی را برای مدیریت چرخه عمر کامپوننتی خود در اختیار توسعه دهندگان قرار می دهد. این چرخههای عمر به کامپوننت اجازه میدهند تا وظایف خاصی را در مراحل مختلف وجودشان، از ایجاد تا حذف، انجام دهند.
در این مقاله، متد های چرخه عمر کامپوننتی کلاس React را بررسی کردهایم. این روشها برای سالها بخش اساسی React بودهاند و همچنان در سناریوهای خاص مرتبط هستند.
شما همچنین با React Hooks آشنا شدید. اینها به متد ترجیحی برای مدیریت state و side effect در برنامه های React تبدیل شده اند. آنها رویکرد شهودی و انعطاف پذیرتری را برای ساخت کامپوننت ارائه می دهند.
در حالی که هوک ها محبوبیت پیدا کرده اند و به طور کلی جایگزین نیاز به کامپوننت های کلاس می شوند، مهم است که توجه داشته باشید که هیچ برنامه ای برای حذف کامپوننتی کلاس از React وجود ندارد. پایگاههای کد موجود و کتابخانههای شخص ثالث ممکن است هنوز از کامپوننتی کلاس استفاده کنند، بنابراین درک هر دو چرخه عمر کامپوننت کلاس و هوک ها امکانپذیر است.
برای توسعه دهندگان React ارزشمند است.
به طور خلاصه، متد ها و هوک های چرخه عمر React برای ساخت برنامههای کاربردی پویا و کارآمد بسیار مهم هستند و طیف وسیعی از گزینهها را برای مدیریت رفتار و state کامپوننت به توسعهدهندگان ارائه میدهند. همانطور که به کاوش و کار با React ادامه می دهید،
متوجه خواهید شد که داشتن درک کامل از چرخه عمر و هوک ها، شما را به یک توسعه دهنده React همه کاره تر و توانمندتر تبدیل می کند.