آموزش React یک کتابخانه قدرتمند جاوا اسکریپت است که برای ساخت رابطهای کاربری پویا و تعاملی توسعه داده شده است. یادگیری یادگیری مفاهیم پایه (Main Concepts) React برای هر توسعهدهندهای که قصد دارد پروژههای قدرتمند و مقیاسپذیر ایجاد کند، ضروری است. این مقاله به شما کمک میکند تا از سطح مبتدی تا پیشرفته با مفاهیم اصلی React آشنا شوید.
کامپوننتها و JSX (Components and JSX)
کامپوننتها (Components) در React اجزای اصلی و قابل استفاده مجددی هستند که برای ساختن بخشهای مختلف رابط کاربری استفاده میشوند. با تقسیم رابط کاربری به کامپوننتهای کوچکتر، کد قابل مدیریتتر، خواناتر، و قابل نگهداریتر میشود. به این ترتیب، هر کامپوننت میتواند یک بخش خاص از صفحه را نمایندگی کند، از یک دکمه ساده گرفته تا یک فرم پیچیده یا یک لیست از محصولات.
در React، دو نوع کامپوننت اصلی وجود دارد:
کامپوننتهای تابعی (Functional Components): این نوع کامپوننتها با استفاده از توابع جاوا اسکریپت ساخته میشوند و به دلیل سادگی و کارایی، بیشتر برای ساخت رابطهای کاربری مورد استفاده قرار میگیرند. برای مدیریت وضعیت داخلی یا استفاده از قابلیتهای اضافی، میتوان از هوکها (مثل useState و useEffect) در کامپوننتهای تابعی استفاده کرد.
کامپوننتهای کلاسی (Class Components): این نوع کامپوننتها با استفاده از کلاسها در جاوا اسکریپت ساخته میشوند و دارای امکانات بیشتری برای مدیریت وضعیت و چرخه حیات هستند. اگرچه React توصیه میکند که از کامپوننتهای تابعی استفاده شود، اما همچنان کامپوننتهای کلاسی در برخی پروژههای قدیمی وجود دارند.
JSX چیست و چگونه کار میکند؟
JSX یک افزونهی زبان جاوا اسکریپت است که به ما اجازه میدهد کد HTML را مستقیماً درون جاوا اسکریپت بنویسیم. این کار، نوشتن رابط کاربری را سادهتر و کدها را خواناتر میکند. به زبان ساده، JSX به شما این امکان را میدهد که هم ساختار رابط کاربری و هم منطق مربوط به آن را در یک فایل بنویسید. در زمان اجرای کد، JSX به صورت خودکار به دستورات جاوا اسکریپت معمولی تبدیل میشود.
چرا JSX مفید است؟
ترکیب HTML و جاوا اسکریپت: با JSX میتوانید ساختار HTML را مستقیماً داخل کد جاوا اسکریپت بنویسید، که باعث میشود کدهای مربوط به رابط کاربری تمیزتر و واضحتر شوند.
استفاده از متغیرها و منطق درون JSX: میتوانید متغیرها، شرطها، و توابع جاوا اسکریپت را درون JSX استفاده کنید تا منطق پیچیدهتری را به رابط کاربری اضافه کنید.
ساختار JSX و کامپوننت
هر کامپوننت معمولاً ورودیهایی به نام props دریافت میکند که برای ارسال داده و تنظیمات به کامپوننت استفاده میشود. این props به کامپوننت اجازه میدهد تا به صورت پویا تغییر کند و بسته به دادههای ورودی، خروجی متفاوتی تولید کند.
مثال ساده:
در این مثال، یک کامپوننت تابعی Welcome داریم که از props برای نمایش نام کاربر استفاده میکند.
function Welcome(props) {
return <h1>سلام، {props.name}</h1>;
}
وقتی این کامپوننت در اپلیکیشن استفاده شود و نام کاربر به عنوان props به آن ارسال شود، به صورت پویا پیام خوشآمدگویی را نمایش میدهد:
function App() {
return <Welcome name="علی" />;
}
در اینجا، کامپوننت Welcome از props.name استفاده میکند تا نام علی را در صفحه نشان دهد. این یک نمونه ساده از استفاده از props برای شخصیسازی محتوای نمایش داده شده در یک کامپوننت است.
استفاده از کامپوننتها و JSX در React، به ما امکان میدهد رابطهای کاربری پیچیده و پویا را با کمترین کد و به صورت کارآمد توسعه دهیم. ترکیب JSX با کامپوننتها به توسعهدهندگان این توانایی را میدهد که رابط کاربری را به راحتی مدیریت کنند و به دلیل قابلیت استفاده مجدد، زمان توسعه را کاهش دهند.
پراپها (Props)
در React، پراپها (Props) ابزاری هستند که به کامپوننتها اجازه میدهند دادهها را از کامپوننتهای والد دریافت کنند و سپس این دادهها را در درون کامپوننتهای فرزند نمایش دهند یا به فرزندان دیگر ارسال کنند. پراپها در واقع شبیه به پارامترهای تابع هستند که به هر کامپوننت ارسال میشوند و به آن اجازه میدهند تا دادههای خارجی را نمایش دهد یا براساس آنها رفتار کند.
ویژگیهای پراپها
غیرقابل تغییر بودن: پراپها درون کامپوننتها فقط برای خواندن استفاده میشوند و نمیتوانند تغییر کنند. این ویژگی باعث میشود که کامپوننتها بتوانند بدون نگرانی از تغییرات دادهها، روی رفتار خود تمرکز کنند. تغییر پراپها تنها از طریق والد انجام میشود و فرزند نمیتواند مقدار آن را تغییر دهد.
قابلیت ارسال به فرزندان: پراپها به صورت سلسله مراتبی عمل میکنند و از والد به فرزند ارسال میشوند. این ویژگی به کامپوننتها این امکان را میدهد که اطلاعات خود را به فرزندان بدهند و براساس آنها رفتار فرزندان را کنترل کنند.
یکطرفه بودن جریان دادهها: دادهها به صورت یکطرفه و تنها از والدین به فرزندان حرکت میکنند. این معماری باعث سادگی و پیشبینیپذیری رفتار دادهها میشود، بهطوری که هر تغییری در دادهها باید در سطح بالاتری از کامپوننتها انجام شود.
کاربرد پراپها در شخصیسازی کامپوننتها
پراپها به شما این امکان را میدهند که کامپوننتهای خود را با دادههای مختلف شخصیسازی کنید و بهجای نوشتن چندین کامپوننت متفاوت، یک کامپوننت عمومی بسازید که با پراپها تغییر میکند. به عنوان مثال، در زیر یک کامپوننت ساده به نام Welcome داریم که از پراپ name برای نمایش پیام خوشآمدگویی استفاده میکند.
مثال:
function Welcome(props) {
return <h1>سلام، {props.name}</h1>;
}
function App() {
return <Welcome name="علی" />;
}
در این مثال:
App به عنوان کامپوننت والد عمل میکند و پراپ name را با مقدار “علی” به کامپوننت Welcome ارسال میکند.
کامپوننت Welcome مقدار پراپ name را دریافت کرده و آن را در درون تگ <h1> نمایش میدهد.
این ساختار به شما اجازه میدهد تا کامپوننت را با پراپهای متفاوت و بدون تغییر در کد داخلی آن، دوباره استفاده کنید.
ارسال چندین پراپ به کامپوننتها
پراپها محدود به یک مقدار نیستند و میتوان چندین پراپ را به کامپوننت ارسال کرد. هر پراپ به عنوان یک ویژگی مجزا به کامپوننت منتقل میشود و به وسیلهی props میتوان به آن دسترسی داشت.
مثال:
function UserProfile(props) {
return (
<div>
<h1>نام: {props.name}</h1>
<p>سن: {props.age}</p>
</div>
);
}
function App() {
return <UserProfile name="علی" age={25} />;
}
در این مثال، پراپهای name و age به کامپوننت UserProfile ارسال میشوند و در آنجا به عنوان props.name و props.age در دسترس هستند.
استفاده از پراپهای پیشفرض (Default Props)
اگر پراپها در والد مشخص نشوند، میتوانیم برای کامپوننتها مقادیر پیشفرض تعیین کنیم. این کار باعث میشود که در صورت عدم ارسال پراپ، مقدار پیشفرض جایگزین شود.
مثال با پراپ پیشفرض:
function Welcome(props) {
return <h1>سلام، {props.name}</h1>;
}
Welcome.defaultProps = {
name: "کاربر ناشناس"
};
در اینجا، اگر Welcome بدون پراپ name استفاده شود، پیام خوشآمدگویی به عنوان “سلام، کاربر ناشناس” نمایش داده خواهد شد.پراپها در React به کامپوننتها این امکان را میدهند که انعطافپذیری بیشتری داشته باشند و بسته به دادههایی که از والدین خود دریافت میکنند، خروجیهای متفاوتی ایجاد کنند. با این روش، میتوان کامپوننتهایی ساخت که هم قابل استفاده مجدد و هم قابل شخصیسازی هستند و بدون تغییر کد داخلی آنها، رفتار و ظاهرشان را تغییر داد.
وضعیت (State)
State یکی از مهمترین مفاهیم در React است و به معنای وضعیتی است که میتواند تغییر کند و رفتار و ظاهر کامپوننتها را در پاسخ به رویدادهای مختلف یا تغییرات دادهها بهروزرسانی کند. برخلاف پراپها (Props) که از والدین به کامپوننت فرزند ارسال میشوند و ثابت و غیرقابل تغییر هستند، State یک ویژگی داخلی در هر کامپوننت است که به آن اجازه میدهد اطلاعاتی را نگهداری و در طول زمان تغییر دهد. این قابلیت برای ساختن رابطهای کاربری تعاملی و پویا بسیار حیاتی است.
تفاوت بین State و Props
State: دادههای داخلی و متغیر کامپوننت است که قابل تغییر بوده و فقط درون همان کامپوننت نگهداری و مدیریت میشود.
Props: دادههایی هستند که از والدین به فرزندان منتقل میشوند و فقط قابل خواندن هستند.
چگونگی مدیریت State در کامپوننتهای تابعی و کلاسی
در React، روشهای مختلفی برای مدیریت State وجود دارد که به نوع کامپوننت بستگی دارد:
در کامپوننتهای تابعی: برای مدیریت State از هوکها استفاده میشود. هوک useState یک تابع است که مقدار ابتدایی State و یک تابع برای بهروزرسانی آن را برمیگرداند. این روش از زمان معرفی React hooks در نسخه ۱۶.۸ به عنوان روش اصلی مدیریت State در کامپوننتهای تابعی شناخته میشود.
مثال:
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>شمارش: {count}</p>
<button onClick={() => setCount(count + 1)}>افزایش</button>
</div>
);
}
در این مثال، count مقدار State و setCount تابعی برای بهروزرسانی آن است. با کلیک روی دکمه، مقدار count افزایش مییابد و رابط کاربری بهروزرسانی میشود.
در کامپوننتهای کلاسی: در کامپوننتهای کلاسی، State به عنوان یک شیء درون سازنده (constructor) تعریف میشود و برای بهروزرسانی آن از متد this.setState استفاده میشود.
مثال:
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
handleClick = () => {
this.setState({ count: this.state.count + 1 });
}
render() {
return (
<div>
<p>شمارش: {this.state.count}</p>
<button onClick={this.handleClick}>افزایش</button>
</div>
);
}
}
در این روش، this.setState مقدار جدیدی برای count تعیین میکند و کامپوننت را دوباره رندر میکند.
اهمیت و کاربرد State در کامپوننتها
State به کامپوننتها اجازه میدهد که پویا باشند و با تغییرات دادهها، رابط کاربری بهروزرسانی شود. به عنوان مثال، در اپلیکیشنهای تعاملی مانند شمارندهها، فرمها، و صفحات کاربری، State به عنوان یک ابزار اصلی برای ذخیره وضعیت داخلی استفاده میشود.
چندین مقدار State در یک کامپوننت
در کامپوننتهای تابعی میتوان از useState برای مدیریت چندین مقدار State استفاده کرد. برای هر مقدار State جدید، یک هوک useState جداگانه تعریف میشود.
مثال:
function UserProfile() {
const [name, setName] = useState("علی");
const [age, setAge] = useState(25);
return (
<div>
<p>نام: {name}</p>
<p>سن: {age}</p>
<button onClick={() => setAge(age + 1)}>افزایش سن</button>
</div>
);
}
در این مثال، دو مقدار State مجزا برای نام و سن کاربر تعریف شده است و میتوان آنها را بهصورت جداگانه بهروزرسانی کرد.
نکاتی درباره مدیریت State
حالت اولیه: مقدار اولیه State بسیار مهم است زیرا تعیینکنندهی شرایط ابتدایی کامپوننت است.
بهروزرسانی State بهصورت غیرهمزمان: در React، تغییرات State بهصورت غیرهمزمان اتفاق میافتد؛ یعنی ممکن است بلافاصله بعد از فراخوانی setState، مقدار State بهروزرسانی نشود.
عدم تغییر مستقیم State: در هیچ حالتی نباید مستقیماً مقدار State را تغییر دهید. بهجای آن از setState یا تابع بهروزرسانی useState استفاده کنید.
State به شما امکان میدهد که کامپوننتهای پویا و تعاملی بسازید. با استفاده از State میتوانید رفتار رابط کاربری را براساس رویدادهای مختلف یا تغییرات دادهها کنترل کنید. این مفهوم اصلی و قدرتمند React به توسعهدهندگان اجازه میدهد تا برنامههایی پیچیده و واکنشگرا را به روشی ساده و موثر ایجاد کنند.
مدیریت رویدادها (Handling Events)
در React، رویدادها به شما اجازه میدهند که به تعاملات کاربر مانند کلیک کردن، تایپ کردن، حرکت ماوس و بسیاری دیگر پاسخ دهید. این رویدادها مشابه رویدادهای مرورگر در جاوا اسکریپت استاندارد هستند اما با تفاوتهای مهمی مدیریت میشوند که استفاده از آنها را در React ساده و قابل اعتماد میکند. در این بخش، نحوهی مدیریت رویدادها و تنظیم عملکردهای پاسخدهنده به رویدادهای مختلف را بررسی میکنیم.
نحوه تعریف رویدادها در React
در React، رویدادها به صورت ویژگیهای JSX تعریف میشوند و نام آنها معمولاً با حروف بزرگ شروع میشود، مانند onClick یا onChange. برخلاف جاوا اسکریپت معمولی که از رشتهها بهعنوان مقادیر رویداد استفاده میکند، در React تابعهایی به عنوان مقادیر رویدادها تعریف میشوند.
مثال ساده از رویداد کلیک:
در این مثال، یک دکمه داریم که هنگام کلیک کاربر، تابع handleClick اجرا میشود و پیام هشدار نمایش میدهد.
function ActionButton() {
function handleClick() {
alert('دکمه کلیک شد!');
}
return <button onClick={handleClick}>کلیک کنید</button>;
}
در این مثال:
رویداد onClick به تابع handleClick متصل شده است.
با کلیک روی دکمه، تابع اجرا شده و پیام هشدار نشان داده میشود.
تفاوت رویدادها در React و جاوا اسکریپت
نامگذاری و استفاده از حروف بزرگ: برخلاف HTML که در آن نام رویدادها با حروف کوچک تعریف میشوند، در React نام رویدادها با حروف بزرگ آغاز میشود. به عنوان مثال، به جای onclick در جاوا اسکریپت، از onClick در React استفاده میشود.
استفاده از تابعها بهجای رشتهها: در جاوا اسکریپت معمولی، مقادیر رویدادها به صورت رشتهها تعریف میشوند، اما در React تابعها بهطور مستقیم به رویدادها اختصاص داده میشوند.
رویدادهای رایج در React
React مجموعهای از رویدادهای استاندارد را فراهم میکند که شامل موارد زیر است:
onClick: هنگام کلیک روی یک عنصر اجرا میشود.
onChange: هنگام تغییر مقدار یک ورودی مانند input یا textarea اجرا میشود.
onSubmit: هنگام ارسال فرم اجرا میشود.
onMouseEnter و onMouseLeave: هنگام ورود و خروج ماوس از روی یک عنصر فعال میشود.
onKeyDown و onKeyUp: هنگام فشار دادن یا رها کردن کلیدهای کیبورد اجرا میشود.
ارسال پارامتر به توابع رویداد
گاهی اوقات نیاز دارید که پارامترهایی را به تابع رویداد ارسال کنید. برای این کار میتوانید از یک تابع ناشناس استفاده کنید تا مقدار مورد نظر را به تابع رویداد ارسال کنید.
مثال با پارامتر:
function ActionButton() {
function handleClick(name) {
alert(`سلام، ${name}!`);
}
return (
<button onClick={() => handleClick('علی')}>
کلیک کنید
</button>
);
}
در این مثال، تابع handleClick یک پارامتر name دریافت میکند و هنگام کلیک، پیام سفارشیشدهای با نام علی نشان داده میشود.
استفاده از preventDefault و stopPropagation
در برخی مواقع ممکن است بخواهید از عملکرد پیشفرض یک رویداد جلوگیری کنید یا از پخش شدن آن در DOM جلوگیری کنید. برای این کار میتوانید از preventDefault و stopPropagation استفاده کنید.
مثال جلوگیری از رفتار پیشفرض:
در اینجا، از preventDefault استفاده میکنیم تا از ارسال فرم جلوگیری کنیم.
function Form() {
function handleSubmit(event) {
event.preventDefault();
alert('فرم ارسال نشد');
}
return (
<form onSubmit={handleSubmit}>
<button type="submit">ارسال</button>
</form>
);
}
در این مثال، بدون استفاده از preventDefault، فرم بهصورت پیشفرض ارسال میشود. با اضافه کردن این خط، از ارسال فرم جلوگیری کرده و پیام سفارشی نمایش داده میشود.مدیریت رویدادها در React یکی از ابزارهای اصلی برای ساختن رابطهای کاربری تعاملی است. با استفاده از این رویدادها، میتوانید به آسانی به واکنشهای کاربر پاسخ دهید و عملکردهای مختلفی را در زمان مناسب اجرا کنید. استفاده از تابعها بهعنوان مقادیر رویدادها در React، مدیریت و خوانایی کد را بهبود میبخشد و ساختار کدها را منظمتر و قابل فهمتر میکند.
رندر کردن شرطی (Conditional Rendering)
رندر کردن شرطی یکی از قابلیتهای مهم در React است که به شما اجازه میدهد بر اساس شرایط خاصی بخشهای مختلفی از رابط کاربری را نمایش دهید یا پنهان کنید. این ویژگی بهویژه در مواردی که لازم است نمایش برخی از محتواها به وضعیت یا دادههای خاصی وابسته باشد، بسیار کاربردی است؛ مانند نمایش پیام خوشآمدگویی برای کاربران واردشده و نمایش دکمه ورود برای کاربران مهمان.
نحوه استفاده از رندر کردن شرطی
رندر کردن شرطی در React با استفاده از عملگرهای شرطی و عبارات منطقی صورت میگیرد. متداولترین روشها برای پیادهسازی رندر شرطی عبارتاند از:
عملگر سهتایی (? :): این عملگر شرطی یک شرط را بررسی میکند و بر اساس نتیجه آن یکی از دو خروجی را برمیگرداند.
عبارات منطقی &&: این روش به شما اجازه میدهد که در صورت برقرار بودن یک شرط، یک بخش از رابط کاربری را نمایش دهید.
شرطهای if-else: این روش برای شرایط پیچیدهتر مناسب است که در آن چندین شرط و گزینههای مختلف مورد نیاز است.
مثالها و روشهای مختلف رندر کردن شرطی
۱. استفاده از عملگر سهتایی (? 🙂
این روش مناسب زمانی است که دو گزینه برای نمایش وجود دارد. مثالی ساده از نمایش پیام خوشآمدگویی یا پیام ورود در صورت ورود کاربر به سیستم:
function UserGreeting(props) {
const isLoggedIn = props.isLoggedIn;
return isLoggedIn ? <h1>خوش آمدید</h1> : <h1>لطفا وارد شوید</h1>;
}
در اینجا:
اگر مقدار isLoggedIn برابر با true باشد، پیام خوشآمدگویی نمایش داده میشود.
اگر مقدار isLoggedIn برابر با false باشد، پیام “لطفا وارد شوید” نمایش داده میشود.
۲. استفاده از عبارات منطقی &&
این روش زمانی مفید است که فقط در صورت برقرار بودن شرطی خاص، بخشی از رابط کاربری نمایش داده شود. بهعنوان مثال، میتوانید یک پیام مخصوص به کاربران واردشده نمایش دهید:
function UserDashboard(props) {
const isLoggedIn = props.isLoggedIn;
return (
<div>
<h1>داشبورد</h1>
{isLoggedIn && <p>به حساب کاربری خود خوش آمدید!</p>}
</div>
);
}
در این مثال، اگر isLoggedIn مقدار true داشته باشد، پیام “به حساب کاربری خود خوش آمدید!” نمایش داده میشود؛ در غیر این صورت، این پیام نمایش داده نخواهد شد.
۳. استفاده از شرطهای if-else
در شرایطی که منطق شرطی پیچیدهتری وجود دارد و بیش از دو گزینه برای نمایش در نظر گرفته شده است، میتوانید از شرطهای if-else داخل تابع استفاده کنید.
مثال:
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <h1>خوش آمدید</h1>;
} else {
return <h1>لطفا وارد شوید</h1>;
}
}
در این مثال، ابتدا شرط isLoggedIn بررسی میشود و در صورت true بودن آن، پیام خوشآمدگویی نمایش داده میشود؛ در غیر این صورت، پیام دیگری نمایش داده میشود.
ترکیب چندین روش رندر کردن شرطی
در برخی مواقع ممکن است نیاز باشد چندین شرط را با هم ترکیب کنید. به عنوان مثال، با استفاده از عملگر && و ? : میتوان همزمان چندین حالت مختلف را مدیریت کرد.
function UserStatus(props) {
const { isLoggedIn, hasMessages } = props;
return (
<div>
<h1>{isLoggedIn ? "خوش آمدید" : "لطفا وارد شوید"}</h1>
{isLoggedIn && hasMessages && <p>شما پیام جدید دارید!</p>}
</div>
);
}
در این مثال:
اگر کاربر وارد شده باشد، پیام خوشآمدگویی نمایش داده میشود و اگر پیام جدیدی داشته باشد، پیام “شما پیام جدید دارید!” نیز نمایش داده خواهد شد.
اگر کاربر وارد نشده باشد، پیام “لطفا وارد شوید” نشان داده میشود.
رندر کردن شرطی در React یکی از راهکارهای قدرتمند برای ایجاد رابطهای کاربری تعاملی و شخصیسازیشده است. این قابلیت به شما امکان میدهد که نمایش یا پنهانسازی محتوای مختلف را به آسانی مدیریت کنید و رابط کاربری خود را بر اساس وضعیت و شرایط مختلف تغییر دهید. با استفاده از روشهای مختلف رندر شرطی، میتوانید کدی تمیزتر و قابل فهمتر ایجاد کنید.
لیستها و کلیدها (Lists and Keys)
در React، لیستها ابزار بسیار مهمی برای نمایش مجموعهای از دادهها هستند، مانند لیستی از کاربران، محصولات یا مقادیر عددی. برای نمایش لیستها از تابع map در جاوا اسکریپت استفاده میشود که به شما اجازه میدهد دادهها را از یک آرایه بگیرید و برای هر آیتم درون آرایه، یک عنصر جدید در JSX ایجاد کنید.
کلیدها (Keys) نیز بخش حیاتی مدیریت لیستها در React هستند. هر آیتم درون لیست باید دارای یک کلید یکتا باشد تا React بتواند بهینهتر عمل کند و در صورت تغییر یا بازسازی لیست، تنها آیتمهای مورد نیاز را بهروزرسانی کند. این کلید به React کمک میکند که هر عنصر را بهصورت منحصر به فرد شناسایی کرده و عملکرد بازدهتری داشته باشد.
اهمیت کلیدها در React
کاهش رندرهای غیرضروری: کلیدها به React کمک میکنند که تشخیص دهد کدام آیتمها تغییر کردهاند و تنها آنها را دوباره رندر کند. به این ترتیب، عملکرد بهبود یافته و منابع سیستم کمتر مصرف میشوند.
مدیریت تغییرات: اگر آیتمی اضافه، حذف یا جابهجا شود، React با استفاده از کلیدها میتواند بهراحتی این تغییرات را شناسایی و مدیریت کند.
پایداری دادهها: کلیدها به React اجازه میدهند که وضعیت یا دادههای مرتبط با هر آیتم را بهتر پیگیری کند، خصوصاً در مواردی که نیاز به نگهداری وضعیت کامپوننتها وجود دارد.
ساختار و نحوهی استفاده از کلیدها
بهترین روش برای انتخاب کلید، استفاده از یک شناسه یکتا برای هر آیتم (مانند شناسهی دیتابیس) است. در صورتی که چنین شناسهای در دسترس نباشد، میتوانید از اندکس (index) آیتم در آرایه استفاده کنید، اما این روش بهطور عمومی توصیه نمیشود مگر در شرایطی که لیست بهندرت تغییر کند.
مثال از نمایش یک لیست ساده با کلیدها
در اینجا لیستی از اعداد داریم که با استفاده از map، یک لیست از عناصر <li> تولید میشود. هر عنصر دارای یک کلید یکتا است که از مقدار خود آیتم استفاده میکند.
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li key={number.toString()}>{number}</li>
);
function NumberList() {
return <ul>{listItems}</ul>;
}
در این مثال:
map برای تکرار روی آرایه numbers و ایجاد یک عنصر <li> برای هر عدد استفاده شده است.
کلیدها با استفاده از key={number.toString()} تعیین شدهاند. این کلید یکتا و بر اساس مقدار هر عدد است، که به React کمک میکند تا لیست را بهینه مدیریت کند.
مثال پیشرفتهتر: لیستی از اشیاء
در اینجا، لیستی از کاربران داریم که دارای ویژگیهای id و name هستند. id هر کاربر به عنوان کلید استفاده میشود.
const users = [
{ id: 1, name: "علی" },
{ id: 2, name: "زهرا" },
{ id: 3, name: "محمد" }
];
function UserList() {
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
در این مثال، user.id به عنوان کلید استفاده میشود، زیرا یک شناسهی یکتا برای هر کاربر است. این روش ایدهآل برای تعیین کلیدهاست، زیرا با تغییر محتوا یا ترتیب لیست، React میتواند بهینهسازیهای بیشتری را انجام دهد.
نکات کلیدی دربارهی کلیدها
همیشه از کلیدهای یکتا برای هر آیتم استفاده کنید تا از تداخل دادهها جلوگیری شود.
اگر شناسهی یکتایی مانند id وجود ندارد، از اندکس استفاده کنید اما تنها در شرایط خاص، چون اندکسها ممکن است در لیستهای پویا باعث مشکلاتی شوند.
کلیدها تنها برای React و بهینهسازی داخلی آن استفاده میشوند و به خود آیتمها یا استایلدهی آنها تاثیری ندارند.
استفاده از لیستها و کلیدها در React به شما امکان میدهد که دادههای پویا و تغییرپذیر را بهصورت بهینه مدیریت کنید. کلیدها به React کمک میکنند که تغییرات را بهدرستی شناسایی و رندرها را به حداقل برساند، در نتیجه عملکرد اپلیکیشن بهبود مییابد و از منابع سیستم بهینهتر استفاده میشود.
فرمها (Forms)
فرمها یکی از اجزای مهم و تعاملی در اپلیکیشنهای وب هستند که امکان دریافت اطلاعات و تعامل کاربر را فراهم میکنند. فرمها میتوانند شامل انواع ورودیها مانند متن، انتخابها، چکباکسها و دکمهها باشند. در React، مدیریت فرمها و دادههای آنها به دو روش کنترلشده (Controlled) و غیرکنترلشده (Uncontrolled) امکانپذیر است. هر یک از این روشها مزایا و کاربردهای خاص خود را دارند.
فرمهای کنترلشده (Controlled Forms)
در فرمهای کنترلشده، ورودیها مستقیماً با state کامپوننت در ارتباط هستند. هر بار که کاربر مقداری را درون ورودی تغییر میدهد، وضعیت (state) بهروزرسانی میشود و دادههای فرم درون state ذخیره میشود. این روش کنترل بیشتری بر دادههای ورودی فراهم میکند و به توسعهدهنده امکان میدهد دادهها را در زمان واقعی بررسی و مدیریت کند.
ویژگیها و مزایای فرمهای کنترلشده
کنترل کامل بر دادههای ورودی: دادههای ورودی بهطور کامل از طریق state قابل دسترسی و کنترل است.
مدیریت آسان تغییرات: هر تغییر در ورودی باعث بهروزرسانی state میشود، بنابراین دادهها در هر لحظه بهروز و دقیق هستند.
مدیریت اعتبارسنجی و فرمتدهی: میتوان بهراحتی قوانین اعتبارسنجی را پیادهسازی کرد و دادهها را پیش از ارسال بررسی و قالببندی کرد.
مثال از یک فرم کنترلشده:
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = { value: '' };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ value: event.target.value });
}
handleSubmit(event) {
alert('یک نام ارسال شد: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
نام:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<button type="submit">ارسال</button>
</form>
);
}
}
در این مثال:
value در state ذخیره شده و ورودی فرم (input) به آن متصل است.
با تغییر کاربر در ورودی، تابع handleChange اجرا و state بهروز میشود.
هنگام ارسال فرم، handleSubmit اجرا و مقدار فعلی state نمایش داده میشود.
فرمهای غیرکنترلشده (Uncontrolled Forms)
در فرمهای غیرکنترلشده، دادهها مستقیماً درون DOM ذخیره میشوند و بهجای مدیریت دادهها از طریق state، از Ref برای دسترسی به مقادیر ورودی استفاده میشود. این روش زمانی مناسب است که نیازی به مدیریت مداوم دادهها درون state ندارید و صرفاً میخواهید دادهها را هنگام ارسال فرم بخوانید.
ویژگیها و مزایای فرمهای غیرکنترلشده
سادگی پیادهسازی: بهویژه در مواردی که دادهها نیازی به بهروزرسانی پیوسته ندارند، فرمهای غیرکنترلشده سادهتر هستند.
عدم نیاز به state: در فرمهای غیرکنترلشده، دادههای ورودی مستقیماً از DOM استخراج میشوند، بنابراین از state کمتری استفاده میشود.
مثال از یک فرم غیرکنترلشده:
class NameForm extends React.Component {
constructor(props) {
super(props);
this.input = React.createRef();
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(event) {
alert('یک نام ارسال شد: ' + this.input.current.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
نام:
<input type="text" ref={this.input} />
</label>
<button type="submit">ارسال</button>
</form>
);
}
}
در این مثال:
بهجای استفاده از state، یک ref (this.input) ایجاد شده است تا به عنصر ورودی دسترسی مستقیم داشته باشد.
مقدار ورودی هنگام ارسال فرم از this.input.current.value استخراج میشود.
انتخاب بین فرمهای کنترلشده و غیرکنترلشده
اگر به اعتبارسنجی فوری، فرمتدهی یا مدیریت دادههای ورودی نیاز دارید، فرمهای کنترلشده مناسبتر هستند.
اگر نیازی به مدیریت مداوم دادهها در state ندارید و فقط میخواهید دادهها را هنگام ارسال فرم بخوانید، فرمهای غیرکنترلشده گزینه مناسبی هستند.
فرمها در React ابزار قدرتمندی برای دریافت و مدیریت دادههای کاربر هستند. انتخاب بین فرمهای کنترلشده و غیرکنترلشده بستگی به نیازهای پروژه و سطح کنترل مورد نیاز بر دادهها دارد. فرمهای کنترلشده به شما امکان میدهند که دادهها را بهدقت کنترل کنید و در لحظه به تغییرات پاسخ دهید، در حالی که فرمهای غیرکنترلشده راهی سریع و ساده برای کار با دادهها بدون نیاز به استفاده مکرر از state فراهم میکنند.
کامپوننتهای کنترل شده و غیرکنترل شده (Controlled and Uncontrolled Components)
در React، کامپوننتهای کنترل شده و کامپوننتهای غیرکنترل شده دو روش متفاوت برای مدیریت و نگهداری دادههای ورودی (مثل ورودیهای فرم) هستند. انتخاب بین این دو روش به نیازهای برنامه و سطح کنترل مورد نیاز بر دادهها بستگی دارد. هر یک از این روشها دارای مزایا و معایب خاص خود هستند که در ادامه توضیح داده میشود.
کامپوننتهای کنترل شده (Controlled Components)
در کامپوننتهای کنترل شده، مقادیر ورودیها از طریق state کنترل میشود. به عبارت دیگر، هر تغییری که کاربر در ورودی ایجاد میکند، مستقیماً state را بهروزرسانی میکند، و مقدار نمایشدادهشده در ورودی از state گرفته میشود. در این روش، دادهها در هر لحظه در state بهروز هستند و میتوانیم بهراحتی به این دادهها دسترسی داشته باشیم یا آنها را تغییر دهیم.
ویژگیها و مزایای کامپوننتهای کنترل شده
کنترل کامل بر روی دادهها: با استفاده از state میتوانید دقیقاً بدانید که مقدار ورودی در هر لحظه چه چیزی است.
مدیریت آسان رویدادها: با بهروزرسانی state، میتوانید به سادگی تغییرات ورودیها را پیگیری کرده و اعتبارسنجی یا فرمتدهی را اعمال کنید.
پیادهسازی اعتبارسنجی آنی: به دلیل دسترسی مستقیم به state، میتوانید اعتبارسنجی را بهصورت لحظهای روی ورودیها اعمال کنید.
مثال از یک کامپوننت کنترل شده
در این مثال، ورودی متنی با state بهصورت کنترل شده مدیریت میشود. هر بار که کاربر مقداری را تایپ میکند، state بهروزرسانی شده و مقدار جدید نمایش داده میشود.
import React, { useState } from 'react';
function ControlledInput() {
const [value, setValue] = useState("");
return (
<input
type="text"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
);
}
در اینجا:
value از state گرفته شده است و در input نمایش داده میشود.
هر تغییر در ورودی با onChange مدیریت میشود و مقدار جدید به state اختصاص مییابد.
کامپوننتهای غیرکنترل شده (Uncontrolled Components)
کامپوننتهای غیرکنترل شده برخلاف کامپوننتهای کنترل شده، دادهها را مستقیماً از DOM میخوانند. در این روش، از Refrences (refs) برای دسترسی به مقدار ورودی استفاده میشود. در این حالت، مقادیر ورودیها بهطور مستقیم در DOM ذخیره میشوند و تنها هنگام نیاز (مثلاً در زمان ارسال فرم) از DOM خوانده میشوند.
ویژگیها و مزایای کامپوننتهای غیرکنترل شده
سادگی پیادهسازی: در صورتی که نیازی به کنترل و پیگیری لحظهبهلحظه دادهها نباشد، این روش سادهتر و سبکتر است.
کاهش نیاز به state: به دلیل عدم نیاز به state برای نگهداری مقادیر، استفاده از این روش در برخی شرایط باعث کاهش پیچیدگی کد میشود.
مثال از یک کامپوننت غیرکنترل شده
در این مثال، از ref برای دسترسی به مقدار ورودی استفاده شده و مقدار ورودی در زمان ارسال فرم خوانده میشود.
import React, { useRef } from 'react';
function UncontrolledInput() {
const inputRef = useRef(null);
function handleSubmit(e) {
e.preventDefault();
alert('مقدار وارد شده: ' + inputRef.current.value);
}
return (
<form onSubmit={handleSubmit}>
<input type="text" ref={inputRef} />
<button type="submit">ارسال</button>
</form>
);
}
در اینجا:
از useRef برای ایجاد یک مرجع (reference) به ورودی استفاده شده است.
مقدار ورودی با استفاده از inputRef.current.value بهدست میآید و در زمان ارسال فرم خوانده میشود.
انتخاب بین کامپوننتهای کنترل شده و غیرکنترل شده
انتخاب بین این دو نوع کامپوننت به نیازهای پروژه و میزان کنترل مورد نیاز بر دادههای ورودی بستگی دارد:
کامپوننتهای کنترل شده مناسب هستند اگر نیاز به اعتبارسنجی فوری، مدیریت رویدادها و دادهها بهصورت بلادرنگ باشد. این روش معمولاً در مواردی که دادهها باید دائماً پیگیری شوند و وضعیت ورودیها بهصورت دقیق مدیریت شود، توصیه میشود.
کامپوننتهای غیرکنترل شده زمانی مناسب هستند که نیازی به پیگیری مستمر دادههای ورودی نیست و دادهها فقط در هنگام نیاز از DOM خوانده میشوند. این روش سادهتر است و در فرمهای ساده که تعاملات کمی با ورودی دارند، میتواند کارآمدتر باشد.
در React، انتخاب بین کامپوننتهای کنترل شده و غیرکنترل شده به نیازهای برنامه و سطح کنترل مورد نیاز بر دادهها بستگی دارد. کامپوننتهای کنترل شده دادهها را از طریق state مدیریت میکنند و به شما کنترل کاملی بر دادهها میدهند، در حالی که کامپوننتهای غیرکنترل شده دادهها را مستقیماً از DOM میخوانند و نیازی به state ندارند.
افزایش کارایی در React (Lifting State Up)
افزایش کارایی در React یا بالا بردن state (Lifting State Up) یکی از الگوهای رایج برای مدیریت وضعیت (state) است که به شما امکان میدهد دادهها را در چندین کامپوننت به اشتراک بگذارید. وقتی چند کامپوننت نیاز دارند که یک داده یا وضعیت خاص را به اشتراک بگذارند، میتوان آن داده را به کامپوننت والد آنها منتقل کرد و سپس از طریق پراپها (props) به کامپوننتهای فرزند ارسال کرد. این روش به کارایی برنامه کمک میکند، زیرا تغییرات در state از یک مکان مرکزی کنترل میشود و منجر به بهروزرسانیهای دقیق و بهینه در رابط کاربری میگردد.
چرا بالابردن state اهمیت دارد؟
بهبود ساختار دادهها و جلوگیری از کپیهای غیرضروری: با متمرکز کردن state در کامپوننت والد، از ایجاد کپیهای غیرضروری دادهها در کامپوننتهای فرزند جلوگیری میشود.
هماهنگی بهتر بین کامپوننتها: وقتی چند کامپوننت به یک داده وابسته هستند، قرار دادن آن داده در سطح بالاتر کمک میکند که تغییرات همزمان و هماهنگ در تمام کامپوننتها اتفاق بیافتد.
کاهش پیچیدگی: انتقال state به سطح بالاتر و استفاده از پراپها برای ارسال داده به کامپوننتهای فرزند، کد را خواناتر و سادهتر میکند و به بهینهسازی عملکرد برنامه کمک میکند.
مثال ساده از بالابردن state
فرض کنید دو کامپوننت داریم که باید یک دمای مشخص را نمایش و به سلسیوس یا فارنهایت تبدیل کنند. در این مثال، دما به عنوان state در والد قرار میگیرد و سپس به دو کامپوننت فرزند ارسال میشود.
javascript
Copy code
import React, { useState } from ‘react’;
function TemperatureInput({ temperature, scale, onTemperatureChange }) {
const scaleNames = { c: ‘سلسیوس’, f: ‘فارنهایت’ };
function handleChange(e) {
onTemperatureChange(e.target.value);
}
return (
<fieldset>
<legend>دمای ورودی به مقیاس {scaleNames[scale]}:</legend>
<input value={temperature} onChange={handleChange} />
</fieldset>
);
}
function Calculator() {
const [temperature, setTemperature] = useState(”);
const [scale, setScale] = useState(‘c’);
function handleCelsiusChange(temp) {
setScale(‘c’);
setTemperature(temp);
}
function handleFahrenheitChange(temp) {
setScale(‘f’);
setTemperature(temp);
}
const celsius = scale === ‘f’ ? (temperature – 32) * (5 / 9) : temperature;
const fahrenheit = scale === ‘c’ ? temperature * (9 / 5) + 32 : temperature;
return (
<div>
<TemperatureInput
scale=”c”
temperature={celsius}
onTemperatureChange={handleCelsiusChange}
/>
<TemperatureInput
scale=”f”
temperature={fahrenheit}
onTemperatureChange={handleFahrenheitChange}
/>
</div>
);
}
در این مثال:
کامپوننت والد (Calculator) وضعیت (state) دما و مقیاس آن را نگه میدارد.
این state به دو کامپوننت فرزند TemperatureInput از طریق پراپها ارسال میشود.
تغییر دما: با تغییر دما در هر کدام از کامپوننتهای فرزند، کامپوننت والد نیز بهروزرسانی میشود، و تغییرات بهصورت خودکار در هر دو ورودی بازتاب داده میشود.
مزایای بالابردن state
یکپارچگی دادهها: با قرار دادن state در یک مکان مرکزی، دادهها در تمام کامپوننتهای وابسته هماهنگ هستند.
بهبود کارایی: چون state در یک کامپوننت والد مدیریت میشود، React میتواند بهینهتر تصمیم بگیرد که کدام بخشهای رابط کاربری نیاز به بهروزرسانی دارند.
کد خواناتر و تمیزتر: با استفاده از بالابردن state، کدهای مربوط به مدیریت دادهها در یک مکان جمعآوری شده و پیچیدگی کد کاهش مییابد.
موارد استفاده مناسب برای بالابردن state
زمانی که چندین کامپوننت نیاز دارند به یک داده مشترک دسترسی داشته باشند.
در مواردی که به همزمانی و هماهنگی بین چندین کامپوننت نیاز است.
وقتی میخواهید اعتبارسنجی یا پردازش دادهها بهصورت مرکزی انجام شود.
بالابردن state یکی از الگوهای مهم در React برای مدیریت وضعیت بین کامپوننتها است. با انتقال state به یک کامپوننت والد، دادهها بهصورت متمرکز مدیریت میشوند، که این روش به بهینهسازی برنامه و بهبود کارایی آن کمک میکند. همچنین، این رویکرد باعث میشود که کد سادهتر و خواناتر باشد و وابستگیهای بین کامپوننتها بهطور موثرتری مدیریت شود.
کودهای JSX و تابع render (JSX and Render Function)
در React، تابع render و زبان نشانهگذاری JSX ابزارهای کلیدی برای ساختن رابط کاربری هستند. تابع render مسئولیت تبدیل کدهای JSX به HTML را دارد و JSX نیز یک Syntax خاص است که امکان نوشتن کدهای HTML را به روشی خواناتر و سادهتر فراهم میکند. این دو ابزار در کنار هم باعث میشوند که توسعهدهندگان بتوانند به راحتی و با کمترین پیچیدگی، اجزای مختلف رابط کاربری را طراحی و مدیریت کنند.
JSX چیست؟
JSX (JavaScript XML) یک ترکیب نحوی خاص است که به شما اجازه میدهد تا کد HTML را مستقیماً درون کد جاوا اسکریپت بنویسید. با JSX، میتوانید ساختار و منطق رابط کاربری را در کنار هم در یک مکان بنویسید، که این امر موجب افزایش خوانایی کد و تسهیل در توسعه میشود.
ویژگیهای JSX
ترکیب جاوا اسکریپت و HTML: به کمک JSX میتوان درون HTML از کد جاوا اسکریپت نیز استفاده کرد و عناصر پویا و تعاملی ایجاد کرد.
کامپایل به کد جاوا اسکریپت استاندارد: مرورگرها JSX را مستقیماً نمیشناسند. بنابراین، ابزارهایی مثل Babel این کدها را به کد جاوا اسکریپت استاندارد کامپایل میکنند.
مثال از JSX:
function Greeting() {
const name = "علی";
return <h1>سلام، {name}!</h1>;
}
در اینجا:
JSX به ما اجازه میدهد تا از کد جاوا اسکریپت ({name}) مستقیماً درون تگ HTML استفاده کنیم.
{name} در زمان رندر شدن، با مقدار متغیر name جایگزین میشود.
تابع render چیست و چگونه کار میکند؟
تابع render در React، مسئول تبدیل JSX به کدهای HTML است و مشخص میکند که چه چیزی در صفحه نمایش داده شود. هر بار که state یا props تغییر میکنند، تابع render مجدداً فراخوانی میشود و React بهطور خودکار بررسی میکند که کدام بخشهای DOM باید بهروزرسانی شوند، که این امر به بهینهسازی عملکرد کمک میکند.
در کامپوننتهای تابعی، render بهصورت ضمنی با فراخوانی تابع کامپوننت اجرا میشود، اما در کامپوننتهای کلاسی، تابع render صریحاً تعریف میشود و خروجی آن مشخص میکند که رابط کاربری چگونه نمایش داده شود.
مثال از تابع render در کامپوننت کلاسی:
class Greeting extends React.Component {
render() {
const name = "علی";
return <h1>سلام، {name}!</h1>;
}
}
در اینجا، تابع render درون یک کامپوننت کلاسی تعریف شده است و JSX درون آن، مشخص میکند که این کامپوننت چگونه در صفحه نمایش داده میشود.
ترکیب JSX و تابع render
سازماندهی بهتر رابط کاربری: با استفاده از تابع render و JSX، میتوانید اجزای رابط کاربری را در بخشهای جداگانه بنویسید و مدیریت کنید. هر بار که state یا props تغییر کنند، این تابع بهروزرسانی شده و رابط کاربری بهطور خودکار بهروز میشود.
استفاده از منطق جاوا اسکریپت درون JSX: میتوانید در JSX از شرطها، متغیرها، و توابع جاوا اسکریپت استفاده کنید تا خروجی رابط کاربری را بهصورت پویا کنترل کنید.
مثال از ترکیب منطق جاوا اسکریپت و JSX در تابع render
function UserGreeting({ isLoggedIn }) {
return (
<div>
{isLoggedIn ? <h1>خوش آمدید</h1> : <h1>لطفا وارد شوید</h1>}
</div>
);
}
در این مثال:
شرط isLoggedIn تعیین میکند که کاربر پیام خوشآمدگویی یا پیام درخواست ورود را ببیند. این ترکیب JSX و منطق جاوا اسکریپت، کد را خواناتر و انعطافپذیرتر میکند.
مزایای استفاده از JSX و تابع render
خوانایی بالا: JSX با ترکیب HTML و جاوا اسکریپت، کدهای پیچیده را خواناتر میکند و نگهداری آنها را سادهتر میکند.
توسعه سریعتر: JSX و تابع render، امکان ایجاد و بهروزرسانی سریع رابط کاربری را فراهم میکنند.
انعطافپذیری: میتوانید منطق جاوا اسکریپت را در JSX استفاده کنید تا اجزای پویا و شرطی را در رابط کاربری نمایش دهید.
در React، تابع render و JSX دو ابزار قدرتمند برای ساخت و مدیریت رابط کاربری هستند. JSX، ساختار کد را شفاف و خوانا میکند و تابع render بهطور دقیق مشخص میکند که هر کامپوننت چگونه و با چه شرایطی باید در صفحه رندر شود. ترکیب این دو ابزار به شما کمک میکند که اپلیکیشنهایی پویا، تعاملی و بهینه بسازید.
نتیجهگیری
React یکی از ابزارهای قدرتمند برای ساخت رابطهای کاربری پویا و تعاملی است که به توسعهدهندگان امکان میدهد برنامههایی مقیاسپذیر و کارآمد ایجاد کنند. در این مقاله، به مفاهیم پایهای React مانند کامپوننتها و JSX، مدیریت وضعیت با استفاده از State، پراپها، رندر کردن شرطی، و کار با فرمها پرداختیم. این مفاهیم اساسی، پایههای توسعه در React را تشکیل میدهند و به شما کمک میکنند تا ساختارهای پیچیده را به روشی ساده و خوانا پیادهسازی کنید.
با استفاده از الگوهایی مانند بالا بردن state برای اشتراکگذاری دادهها بین کامپوننتها و انتخاب بین کامپوننتهای کنترل شده و غیرکنترل شده، میتوانید برنامههایی بسازید که هم در کارایی و هم در خوانایی و نگهداری کد بهینه باشند. همچنین، استفاده از JSX و تابع render، ترکیبی انعطافپذیر و قابل درک را برای نمایش و بهروزرسانی رابط کاربری فراهم میکند.
آشنایی با این مفاهیم پایهای به شما این امکان را میدهد که بهعنوان یک توسعهدهندهی React، بهطور موثرتری با ابزارها و قابلیتهای این کتابخانه کار کنید و پروژههایی حرفهایتر و کاربرپسندتر ایجاد کنید.
