دیزاین پترن های ری اکت ! بهترین Design Pattern در ری اکت کدامند ؟!
در دنیای برنامه نویسی، به خصوص وقتی از فریمورک ها و کتابخانه های مدرنی مثل ری اکت استفاده می کنیم، همیشه دنبال راه هایی هستیم که کدهای خودمون رو تمیزتر و بهینه تر بنویسیم. دیزاین پترن ها یا الگوهای طراحی به ما کمک می کنن که به یک ساختار مشخص برسیم و از کدی که یک بار نوشتیم، راحت تر استفاده کنیم. دیزاین پترن های ری اکت مجموعه ای از اصول و روش هایی هستن که باعث میشن کدمون مقیاس پذیرتر، انعطاف پذیرتر و حتی خوندنش راحت تر باشه!
اما سوالی که مطرح میشه اینه که بهترین دیزاین پترن های React کدوم ها هستن؟ آیا لازمه همه این الگوها رو تو پروژه هامون استفاده کنیم؟ یا می تونیم با چندتاشون کار رو راه بندازیم؟
این مقاله، به بررسی مهم ترین و بهترین دیزاین پترن های ری اکت می پردازه و به شما کمک می کنه تا بفهمید چه زمانی از کدوم الگو استفاده کنید.
۱. کامپوننت های قابل استفاده مجدد (Reusable Components)
اولین و شاید مهم ترین الگوی طراحی در ری اکت، طراحی کامپوننت های قابل استفاده مجدد هست. ری اکت بر اساس کامپوننت ها ساخته شده و وقتی کامپوننتی رو طوری طراحی می کنید که توی جاهای مختلف پروژه تون به راحتی بتونید ازش استفاده کنید، به شدت در وقت و انرژی تون صرفه جویی می کنید.
مثلاً تصور کنید که دکمه ای دارید که توی جاهای مختلف اپلیکیشن ازش استفاده می شه؛ اگه هر بار بخواید این دکمه رو از صفر طراحی کنید، هم وقت زیادی از دست می دید، هم احتمالاً هر بار با استایل و ویژگی های مختلفی روبرو میشید که نظم کدتون رو به هم میریزه.
- چطور بسازیم؟ برای ساختن یک کامپوننت قابل استفاده مجدد، باید مطمئن بشید که این کامپوننت تا حد امکان وابستگی های کمتری داره و پارامترهایی مثل props رو برای تنظیمات قابل تغییر دریافت میکنه. مثلاً میتونید یه دکمه عمومی طراحی کنید که بر اساس prop هایی مثل
color
،size
وonClick
رفتار و ظاهرش تغییر کنه.
اینطوری هم میتونید از همون کامپوننت برای دکمه های مختلف استفاده کنید و هم وقتی نیاز به تغییر کوچیکی داشتید، فقط کد همون کامپوننت رو ویرایش کنید.
// Button.js
import React from 'react';
const Button = ({ text, color, size, onClick }) => {
return (
);
};
export default Button;
این کامپوننت را میتوانید در بخش های مختلف برنامه استفاده کنید:
// App.js
import React from 'react';
import Button from './Button';
const App = () => {
return (
);
};
export default App;
۲. الگوی کانتینر و پرزنتیشنال (Container and Presentational Pattern)
الگوی کانتینر و پرزنتیشنال به شما کمک میکنه که منطق برنامه و نحوه نمایش داده ها رو از هم جدا کنید. این کار باعث میشه کدتون تمیزتر و فهمش راحت تر بشه. تو این الگو، دو نوع کامپوننت داریم:
کامپوننت های پرزنتیشنال: این کامپوننت ها فقط مسئول نمایش داده ها هستن و هیچ گونه منطق پیچیده ای توشون وجود نداره. این نوع کامپوننت ها معمولا فقط prop های ورودی رو دریافت میکنن و با استفاده از اون ها، اطلاعات رو نمایش میدن.
کامپوننت های کانتینر: این کامپوننت ها منطق برنامه رو در بر می گیرن و داده ها رو از منابع مختلف (مثل API) دریافت میکنن. اون ها معمولاً از State استفاده میکنن و بعد از آماده سازی داده ها، اون ها رو به کامپوننت های پرزنتیشنال پاس می دن تا نمایش داده بشن.
این الگو به شما کمک می کنه تا کدتون رو بهتر سازماندهی کنید و در صورت نیاز به تغییر منطق برنامه، تنها بخش کانتینر رو ویرایش کنید و نیازی به تغییر در کامپوننت های نمایشی نداشته باشید.
در این الگو، یک کانتینر برای مدیریت دادهها و یک کامپوننت پرزنتیشنال برای نمایش دادهها داریم :
// UserContainer.js
import React, { useState, useEffect } from 'react';
import UserList from './UserList';
const UserContainer = () => {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => response.json())
.then((data) => setUsers(data));
}, []);
return ;
};
export default UserContainer;
// UserList.js (Presentational Component)
import React from 'react';
const UserList = ({ users }) => {
return (
{users.map((user) => (
- {user.name}
))}
);
};
export default UserList;
۳. دیزاین پترن Higher-Order Components (HOC)
یکی دیگه از دیزاین پترن های بسیار پرکاربرد در ری اکت، الگوی Higher-Order Components یا به اختصار HOC هست. این الگو به ما کمک میکنه که بدون تغییر در ساختار اصلی یک کامپوننت، ویژگی ها و قابلیت های جدیدی بهش اضافه کنیم.
HOC در واقع یک تابعه که یک کامپوننت رو به عنوان ورودی دریافت و یک کامپوننت جدید رو به عنوان خروجی برمی گردونه که ویژگی های اضافی داره.
این الگو مخصوصاً زمانی کاربرد داره که بخوایم کدهای تکراری رو در چندین کامپوننت کاهش بدیم.
- مثال کاربردی: فرض کنید چندین کامپوننت دارید که همگی نیاز دارن اطلاعات کاربر رو از یک API دریافت کنن. به جای این که در هر کامپوننت به طور جداگانه کد API رو بنویسید، می تونید یک HOC بسازید که این منطق رو مدیریت کنه و کامپوننت های مختلف رو با این قابلیت بپوشونه.
اینطوری هم کدتون تمیزتر میشه و هم در صورت نیاز به تغییر در منطق API، تنها یک بار در HOC تغییرات رو اعمال میکنید.
در این مثال، یک HOC ایجاد میکنیم که برای کامپوننت ها ویژگی بارگذاری (Loading) اضافه میکنه:
// withLoading.js
import React from 'react';
const withLoading = (WrappedComponent) => {
return ({ isLoading, ...props }) => {
if (isLoading) return در حال بارگذاری...
;
return ;
};
};
export default withLoading;
// UserListWithLoading.js
import withLoading from './withLoading';
import UserList from './UserList';
const UserListWithLoading = withLoading(UserList);
// استفاده در یک کامپوننت
import React, { useState, useEffect } from 'react';
const UserContainer = () => {
const [users, setUsers] = useState([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users')
.then((response) => response.json())
.then((data) => {
setUsers(data);
setIsLoading(false);
});
}, []);
return ;
};
export default UserContainer;
برای درک بهتر HOC پیشنهاد میکنم مقاله HOC در ری اکت رو مطالعه کنید.
۴. دیزاین پترن Render Props
Render Props یک دیزاین پترن در ری اکت محسوب میشه که به شما این امکان رو میده تا منطق مشترک بین کامپوننت ها رو به اشتراک بذارید.
این الگو به جای این که از HOC استفاده کنه، یک تابع رو به عنوان prop به کامپوننت ها پاس میده تا کنترل کامل روی نحوه نمایش (render) داده ها داشته باشن.
با استفاده از الگوی طراحی Render Props، میتونید کامپوننت هایی بسازید که وظایف پیچیده ای رو انجام میدن، بدون این که نمایش داده های اون ها محدود بشه.
- مثال: تصور کنید که یک کامپوننت دارید که وضعیت آنلاین یا آفلاین بودن کاربر رو نمایش میده. با استفاده از Render Props، می تونید تابعی به عنوان prop به این کامپوننت پاس بدید که کنترل نمایش وضعیت کاربر رو به کامپوننت فرزند بسپاره. این کار باعث میشه که منطق کدتون یکپارچه بمونه و در عین حال، انعطاف لازم رو داشته باشه.
در این مثال، از Render Props برای مدیریت وضعیت موس استفاده میکنیم :
// MouseTracker.js
import React, { useState } from 'react';
const MouseTracker = ({ render }) => {
const [position, setPosition] = useState({ x: 0, y: 0 });
const handleMouseMove = (e) => {
setPosition({ x: e.clientX, y: e.clientY });
};
return {render(position)};
};
export default MouseTracker;
// استفاده از MouseTracker
import React from 'react';
import MouseTracker from './MouseTracker';
const App = () => {
return (
(
مختصات موس: X: {position.x}, Y: {position.y}
)}
/>
);
};
export default App;
۵. الگوی Context API برای مدیریت استیت ها
Context API یکی از روش های استاندارد ری اکت برای مدیریت استیت هاست و به شما کمک میکنه تا داده ها و وضعیت ها رو بدون نیاز به prop drilling (پاس دادن props به کامپوننت های لایه های مختلف) به کامپوننت های فرزند برسونید.
استفاده از این الگو به خصوص وقتی پروژه ای بزرگ دارید و می خواید داده ها به صورت یکپارچه بین کامپوننت های مختلف به اشتراک گذاشته بشه، بسیار مفیده.
- چرا استفاده کنیم؟ Context API زمانی به کار میاد که نیاز داریم داده ها بین چندین کامپوننت به اشتراک گذاشته بشن، اما نمیخوایم که propها رو از یک لایه به لایه های بعدی پاس بدیم.
این کار نه تنها کد رو پیچیده می کنه، بلکه باعث میشه هر تغییری در props، موجب render مجدد کامپوننت های غیرضروری بشه.
در این مثال، از Context API برای اشتراکگذاری اطلاعات کاربر بین کامپوننتهای مختلف استفاده میکنیم :
// UserContext.js
import React, { createContext, useState } from 'react';
export const UserContext = createContext();
export const UserProvider = ({ children }) => {
const [user, setUser] = useState({ name: 'کاربر مهمان', age: 30 });
return (
{children}
);
};
// Profile.js
import React, { useContext } from 'react';
import { UserContext } from './UserContext';
const Profile = () => {
const { user } = useContext(UserContext);
return (
نام کاربر: {user.name} - سن: {user.age}
);
};
export default Profile;
// App.js
import React from 'react';
import { UserProvider } from './UserContext';
import Profile from './Profile';
const App = () => {
return (
);
};
export default App;
برای درک بهتر این Design Pattern و Context api پیشنهاد میکنم مقاله Context API در ری اکت رو مطالعه کنید.
۶. الگوی Custom Hooks برای جداسازی منطق
یکی از ویژگی های جدید و محبوب در ری اکت، استفاده از Custom Hooks هست که به شما این امکان رو میده تا منطق مختلفی رو در کامپوننت ها به اشتراک بذارید و کدهای خودتون رو ماژولارتر کنید.
Custom Hooks در واقع توابعی هستن که از قابلیت های Hookهای ری اکت (مثل useState
و useEffect
) استفاده میکنن و میتونن منطق خاصی رو برای کاربردهای مشخصی بسته بندی کنن.
- مثال کاربردی: فرض کنید چندین کامپوننت دارید که نیاز دارن به داده های یک API دسترسی داشته باشن و داده ها رو در استیت ذخیره کنن.
به جای اینکه منطق فراخوانی API رو در هر کامپوننت جداگانه بنویسید، می تونید یک Custom Hook بسازید که این منطق رو مدیریت کنه.
با این کار هم کدتون تمیزتر میشه و هم وقتی نیاز به تغییر داشته باشه، فقط کافیه منطق موجود در Custom Hook رو ویرایش کنید.
در این مثال، یک Custom Hook به نام useFetch
برای دریافت دادهها از API ایجاد میکنیم :
// useFetch.js
import { useState, useEffect } from 'react';
const useFetch = (url) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(url)
.then((response) => response.json())
.then((data) => {
setData(data);
setLoading(false);
});
}, [url]);
return { data, loading };
};
export default useFetch;
// استفاده از useFetch در کامپوننت
import React from 'react';
import useFetch from './useFetch';
const UserList = () => {
const { data: users, loading } = useFetch('https://jsonplaceholder.typicode.com/users');
if (loading) return در حال بارگذاری...
;
return (
{users.map((user) => (
- {user.name}
))}
);
};
export default UserList;
اگه با Custom Hook آشنا نیستید پیشنهاد میکنم مقاله Custom Hook در React رو مطالعه کنید.
نتیجه گیری
استفاده از Design Pattern در ری اکت به شما کمک می کنه تا کدی تمیزتر، انعطاف پذیرتر و مقیاس پذیرتر داشته باشید.
الگوهایی مثل Reusable Components، HOC، Render Props، Context API و Custom Hooks به شما این امکان رو میدن که کدهای تکراری رو به حداقل برسونید و برنامه هایی با کارایی بالا و ساختار منسجم بسازید.
بسته به نیاز پروژه و سطح پیچیدگی، می تونید از این دیزاین پترن ها به صورت جداگانه یا ترکیبی استفاده کنید و از مزایای هر کدوم بهره ببرید.
راستی دیزاین پترن با دیزاین سیستم متفاوته، اگه با تفاوتشون آشنا نیستید سوالات متداول سکشن پایین رو بخونید..
امیدوارم که مفهوم Design Pattern در ری اکت براتون حسااابی مفید واقع شده باشه 🙂
دیزاین پترن در ریکت به شما کمک میکنه کدی تمیزتر، سازمان یافته تر و راحت تر برای نگهداری بنویسید.
وقتی که پروژه بزرگ تر میشه، دیزاین پترن ها باعث میشن بخش های مختلف پروژه بدون اختلال در همدیگه، بروزرسانی و تغییر پیدا کنن.
هر وقت که قراره همون عنصر (مثلاً دکمه، فرم، یا بخش نمایش اطلاعات) رو چندین بار در قسمت های مختلف پروژه استفاده کنید، از کامپوننت های قابل استفاده مجدد بهره بگیرید.
این کار نه تنها کدتون رو سبک تر میکنه، بلکه باعث میشه مدیریت و تغییرات آینده خیلی آسون تر بشه.
HOC یه تابعه که یک کامپوننت رو به عنوان ورودی می گیره و یه کامپوننت جدید با ویژگی های اضافه شده برمی گردونه.
این الگو برای مواقعی مناسبه که می خوایم رفتار یا ویژگی خاصی رو در چندین کامپوننت به اشتراک بذاریم، بدون اینکه ساختار اصلی اون ها رو تغییر بدیم.
مثلاً اضافه کردن قابلیت بارگذاری داده یا مدیریت استیت در چند کامپوننت.
Render Props به شما این امکان رو میده که منطق و نحوه نمایش داده ها رو از هم جدا کنید.
این الگو انعطاف پذیری زیادی ایجاد میکنه، چون کامپوننت فرزند میتونه داده های پردازش شده رو از کامپوننت والد بگیره و نمایش دلخواه خودش رو پیاده کنه. برای پروژه هایی که نیاز به شخصی سازی زیاد دارن، این الگو عالیه.
Context API یه راه ساده برای اشتراک گذاری داده ها بین چندین کامپوننت هست، بدون اینکه لازم باشه props رو به صورت زنجیره ای (prop drilling) از والد به فرزند پاس بدیم. این کار باعث میشه کدتون ساده تر بشه و مشکلات پیچیدگی propها به حداقل برسه.
اگر پروژه شما پیچیدگی زیادی داره و قراره داده ها و منطق برنامه از نمایش جدا بشه، الگوی پرزنتیشنال و کانتینر کمک میکنه تا ساختار کد تمیز و واضح باشه.
این الگو باعث میشه کدها برای تست و نگهداری راحت تر بشن و مانع از درهم تنیدگی منطق و نمایش بشه.
برای پروژه های بزرگ معمولاً ترکیب Context API و Custom Hooks توصیه میشه. Context API به شما کمک میکنه تا استیت ها رو به راحتی در کامپوننت های مختلف به اشتراک بذارید و با استفاده از Custom Hooks میتونید این منطق رو بهینه تر و تمیزتر نگه دارید. اگر حجم داده ها خیلی زیاده، می تونید به سراغ کتابخانه هایی مثل Redux هم برید.
گاهی استفاده از دیزاین پترن ها میتونه به جای بهبود کد، پیچیدگی ایجاد کنه، به خصوص در پروژه های کوچیک یا پروژه هایی که نیاز به ساختاردهی پیچیده ندارن.
استفاده بی جا از پترن ها باعث میشه کدتون سنگین تر بشه و درک و نگهداریش سخت تر بشه.
انتخاب دیزاین پترن بستگی به نیاز پروژه و پیچیدگی منطق برنامه داره. مثلاً اگر با prop drilling مشکل دارید، Context API کمک میکنه. اگر کدهای تکراری زیادی دارید، Reusable Components و Custom Hooks راه حل مناسبی هستن.
دیزاین پترن و دیزاین سیستم دو مفهوم متفاوت هستن که هر کدوم نقش خاصی در فرآیند طراحی و توسعه دارن.
۱. دیزاین پترن (Design Pattern)
دیزاین پترن ها الگوهایی برای حل مشکلات رایج در کدنویسی و طراحی ساختار برنامه هستن. این الگوها، ساختار و اصولی ارائه میدن که به توسعه دهندگان کمک میکنه تا کدهایی مقیاسپذیر، خوانا و قابل نگهداری بنویسن.
دیزاین پترن ها بیشتر روی ساختار کد و نحوه تعامل و ارتباط بین بخشهای مختلف تمرکز دارن. مثلاً در ری اکت، دیزاین پترنهایی مثل Higher-Order Components، Render Props و Context API به شما کمک میکنن تا منطق پیچیده رو به شکل قابل مدیریت و منظم بنویسید.
۲. دیزاین سیستم (Design System)
دیزاین سیستم یه مجموعه جامع از راهنماها، قوانین و عناصر بصری برای طراحی محصولاته. این سیستم شامل رنگها، تایپوگرافی، دکمهها، آیکونها، کامپوننتهای UI و حتی دستورالعملهای طراحی مثل استایل ها و رفتار های تعاملی میشه.
دیزاین سیستم به تیم های طراحی و توسعه کمک میکنه که بتونن عناصر و کامپوننت های مشابه رو با استایل و ظاهر یکپارچه در پروژههای مختلف استفاده کنن.
در نتیجه، دیزاین پترن بیشتر به برنامه نویسی و معماری کد مربوطه، در حالی که دیزاین سیستم برای هماهنگی و یکپارچگی در طراحی و تجربه کاربری به کار میره.
درباره احمد احمدنژاد
من یه برنامه نویس و توسعه دهنده وب هستم که عاشق دنیای صفر و یکم❤️
نوشتههای بیشتر از احمد احمدنژاد2 دیدگاه
به گفتگوی ما بپیوندید و دیدگاه خود را با ما در میان بگذارید.
عالییی توضیح دادید🌹🌹🌹
خوشحالم که براتون مفید بوده 🙂
موفق باشی