چگونه یک کامپوننت مدال قابل استفاده مجدد در React ایجاد کنیم
هنگام استفاده از React، سعی می کنیم تا آنجا که می توانیم اجزای قابل استفاده مجدد ایجاد کنیم تا تعداد کامپوننت ها و تکرار را محدود کنیم. این کد شما را "DRY" نگه می دارد.
DRY مفهومی است که ممکن است با آن برخورد کرده باشید - به معنای "خودت را تکرار نکن". DRY یک اصل کد نویسی است که شما را تشویق می کند تا تکرار کد را با استفاده از انتزاعاتی مانند توابع یا ماژول ها به حداقل برسانید.
این مهم است زیرا افزونگی را کاهش میدهد، نگهداری کد را آسانتر میکند، خوانایی را بهبود میبخشد و خطر خطا را در طول بهروزرسانی کاهش میدهد.
این مقاله چه چیزی را پوشش خواهد داد؟
در این مقاله یاد خواهید گرفت:
چگونه با استفاده از React و CSS یک مودال بسازیم.
چگونه می توان اطمینان حاصل کرد که مودال می تواند در چندین سناریو، محتوا و سبک مورد استفاده مجدد قرار گیرد.
نحوه ادغام توابع حالت و پاسخ به تماس در مدال
فهرست مطالب
این مقاله چه چیزی را پوشش خواهد داد؟
چه زمانی از useEffect استفاده می کنیم؟
نحوه استفاده از مدال قابل استفاده مجدد
مؤلفه اصلی مدال
در این بخش از React برای ساختن یک کتابخانه کامپوننت استفاده می کنیم. الگوهای متعددی وجود دارد که می توانید برای انجام این کار از آنها پیروی کنید، اما یکی از موارد مورد علاقه من الگوی طراحی اتمی است.
import React, {useEffect} from 'react' ; import './Modal.css' interface Props { open: boolean ; cancelFn?: () => void ; primaryFn?: () => void ; closeIcon?: string ; content?: React.ReactNode; titleContent?: React.ReactNode; className?: string ; } export const Modal: React.FC<Props> = ( props ) => { const {open, cancelFn, primaryFn, closeIcon, titleContent, content} = props; // simple useEffect to capture ESC key to close the modal useEffect( () => { const handleKeyDown = ( e: KeyboardEvent ) => { if (e.key === 'Escape' && open) { if (cancelFn) { cancelFn(); } } }; document .addEventListener( 'keydown' , handleKeyDown); return () => document .removeEventListener( 'keydown' , handleKeyDown); }, [open, cancelFn]); if (!open) return null ; return ( <div className= "modalBackground" > <div className= "modalContainer" > {titleContent && (<div className= "title" > {titleContent} <div className= "titleCloseBtn" > <button onClick={cancelFn}>{closeIcon ?? 'X' }</button> </div> </div> )} <div className= "body" > {content} </div> <div className= "footer" > {secondaryFn && ( <button onClick={secondaryFn} id= "cancelBtn" > Cancel </button> )} {primaryFn && ( <button onClick={primaryFn}>Continue</button> )} </div> </div> </div> ); };
.modalBackground { width : 100vw ; height : 100vh ; background-color : rgb( 33 , 33 , 33 , 0.9 ); position : fixed; display : flex; justify-content : center; align-items : center; } .modalContainer { display : flex; flex-direction : column; border-radius : 20px ; background-color : white; box-shadow : rgba( 0 , 0 , 0 , 0.35 ) 0px 5px 15px ; } .modalContainer .title { display : flex; flex-direction : row; text-align : center; align-items : center; justify-content : space-between; padding : 8px ; border-top-right-radius : 20px ; border-top-left-radius : 20px ; background-color : #FFE936 ; } .titleCloseBtn { display : flex; justify-content : flex-end; } .titleCloseBtn button { font-size : 0.3rem ; } .titleCloseBtn button { background-color : transparent; border : none; font-size : 25px ; cursor : pointer; } .modalContainer .body { flex : 1 ; padding : 16px ; display : flex; flex-direction : column; justify-content : center; align-items : center; font-size : 1rem ; text-align : center; } .modalContainer .footer { display : flex; justify-content : center; align-items : center; } .modalContainer .footer button { width : 150px ; height : 45px ; margin : 10px ; border : none; background-color : cornflowerblue; color : white; border-radius : 8px ; font-size : 20px ; cursor : pointer; } #cancelBtn { background-color : crimson; }
کد بالا جزء اصلی مودال است. بیایید آن را تجزیه کنیم.
رابط Props
interface Props { open: boolean ; cancelFn?: () => void ; primaryFn?: () => void ; closeIcon?: string | React.ReactNode; content?: React.ReactNode; titleContent?: React.ReactNode; }
در این رابط (که ما به مؤلفه Modal
منتقل می کنیم) داریم:
open
: یک مقدار بولی که نشان می دهد که آیا مدال باید نشان داده شود یا نه. یک روش متداول برای روشن یا خاموش کردن مودال.
cancelFn
: یک پارامتر اختیاری (که با ?
مشخص می شود) که عملکرد برگشت تماس را برای زمانی که دکمه ثانویه فشار داده می شود ارائه می دهد. به عنوان مثال، عملکرد cancel
برای بستن مدال یا لغو یک عمل.
primaryFn
: یک پارامتر اختیاری است که عملکرد برگشت تماس را برای زمانی که دکمه اصلی فشار داده می شود، ارائه می دهد. برای مثال، ok
، confirm
یا submit
عمل کرد.
closeIcon
: یک پارامتر اختیاری است که نمادی را برای استفاده به عنوان دکمه بستن بالا سمت راست برای مدال ارائه می دهد. به عنوان مثال، می توانید از دایره ای با X یا شکل دیگری از یک دکمه استفاده کنید.
content
: یک پارامتر اختیاری که محتوای درونی مدال را فراهم می کند. این می تواند به سادگی یک تگ <p/>
برای یک عنصر <form/>
کامل باشد.
titleContent
: یک پارامتر اختیاری که محتوایی را برای قرار گرفتن در بخش عنوان مدال فراهم میکند. این می تواند هر چیزی باشد، از متن گرفته تا تصویر لوگو، هر چیزی که می خواهید.
نشانه گذاری
نشانه گذاری بسیار ساده است، برای هر بخش (عنوان، محتوا و اقدامات) به همراه برخی منطق رندر شرطی divs
وجود دارد.
یعنی:
{titleContent && ( <div className= "title" > {titleContent} <div className= "titleCloseBtn" > <button onClick={secondaryFn}>{closeIcon ?? 'X' }</button> </div> </div> )}
ما از نحو ارزیابی اتصال کوتاه استفاده کردیم تا تحلیل کنیم که آیا ویژگی titleContent
توسط توسعه دهنده تعریف شده است یا خیر. اگر چنین باشد، عنوان مدال ارائه می شود. اگر نه، بخش عنوان حذف می شود.
این رویکرد به پیکربندی انعطافپذیر مودال اجازه میدهد، به شما این امکان را میدهد که بخشهایی مانند عنوان، محتوا یا اقدامات را به راحتی اضافه یا حذف کنید.
برای مثال، یک مدال تأیید ممکن است فقط به عنوانی مانند «مطمئنید؟» نیاز داشته باشد. و دکمههای عمل مانند «بله» یا «خیر»، بدون محتوای اضافی.
React useEffect
اگر با useEffect
آشنایی ندارید و قصد دارید بیشتر از React استفاده کنید، به شدت توصیه می کنم در مورد آن اینجا بخوانید، زیرا یکی از ستون های اصلی اکوسیستم React است.
در اصل، useEffect
مانند کمکی است که مطمئن می شود کارها را در زمان مناسب در برنامه خود انجام می دهید.
چه زمانی از useEffect
استفاده می کنیم؟
هنگامی که می خواهید چیزی بلافاصله پس از آماده شدن برنامه شما اتفاق بیفتد:
مثال: وقتی برنامه باز میشود و میخواهید اطلاعاتی را از اینترنت دریافت کنید (مانند بارگیری دستور العملها برای شام).
وقتی چیزی یک متغیر حالت یا پایه ورودی تغییر می کند و شما می خواهید کاری را بعد از آن تغییر انجام دهید.
وقتی برنامه شما بسته یا پاک می شود.
در React App خود، یک useEffect
Hook ایجاد کردهایم که پس از بارگیری مؤلفه مدال اجرا میشود. useEffect
به سادگی یک کنترل کننده رویداد keydown
را به document
(صفحه/DOM) متصل می کند، که به تمام کلیدهایی که روی صفحه فشار داده می شوند گوش می دهد و سپس تحلیل می کند که آیا کلید ESC
است یا خیر.
اگر این کلید ESC
باشد، تابع secondaryFn
را که به modal منتقل شده است فراخوانی می کند. در مورد ما، این تابعی است که مدال را می بندد. دستور return
، کنترل کننده رویداد را در حالت unmount حذف می کند (زمانی که modalOpen
false
است).
نحوه استفاده از مدال قابل استفاده مجدد
import './App.css' import {useState} from "react" ; import {Modal} from "./components/molecules/Modal" ; function App ( ) { const [modalOpen, setModalOpen] = useState( false ); return ( <div className= "App" > <h1>Hey, click on the button to open the modal.</h1> <button className= "openModalBtn" onClick={ () => setModalOpen( true )}> Open </button> <Modal open={modalOpen} titleContent={<h1> Close </h1>} secondaryFn={ () => setModalOpen( false )} content={ <> <h2>This is a modal</h2> <p>You can close it by pressing Escape key, pressing close, or clicking outside the modal.</p> </> } /> </div> ); } export default App
شکستن آن
در کد بالا، یک مولفه دکمه ای داریم که مدال را برای نمایش فعال می کند. این کار با به روز رسانی متغیر useState
modalOpen
انجام می شود. تنظیم این مورد روی true
باعث می شود که مولفه Modal
دیده شود.
در ادامه کد، مؤلفه Modal
را پیادهسازی کردیم و آپشن های مربوطه را در مدال ارسال کردیم: یک عنوان، محتوای بدنه، و یک دکمه ثانویه (ما یک تابع اصلی را پاس نکردیم). این مودال زیر را نشان می دهد:
با استفاده از همان کامپوننت، میتوانیم آن را با هم ترکیب کنیم و یک مدال تأیید مانند این بسازیم:
جایگزینی اجرای مودال قبلی با:
<Modal open={modalOpen} titleContent={<h1> Are you sure? </h1>} cancelFn={ () => setModalOpen( false )} primaryFn={ () => { alert( " You deleted everything everything" ); setModalOpen( false ); }} content={ <> <h4>Do you really want to delete everything?</h4> </> } />
در اینجا شما آن را دارید، یک مؤلفه Modal
با امکانات و پیکربندی های بی پایان دارید، بسته به اینکه چه محتوایی را به هر ناحیه از مدال منتقل می کنید.
بهبودهای اضافی
برخی از پیشرفت های اضافی وجود دارد
تعویض دکمه های لغو و اصلی
به جای ارسال آپشن های cancelFn
و primaryFn
، میتوانید یک مؤلفه کامل حاوی دکمهها یا هر مؤلفه دیگر فوتر را ارسال کنید.
کد به روز شده باید به شکل زیر باشد:
import React, { useEffect } from 'react' ; import './Modal.css' ; interface Props { open: boolean ; escFn: () => void ; closeIcon?: string ; content?: React.ReactNode; titleContent?: React.ReactNode; className?: string ; actions?: React.ReactNode; // This will be used to pass buttons or other actions as children } export const Modal: React.FC<Props> = ( props ) => { const { open, closeIcon, titleContent, content, actions } = props; useEffect( () => { const handleKeyDown = ( e: KeyboardEvent ) => { if (e.key === 'Escape' && open) { } }; document .addEventListener( 'keydown' , handleKeyDown); return () => document .removeEventListener( 'keydown' , handleKeyDown); }, [open]); if (!open) return null ; return ( <div className= "modalBackground" > <div className= "modalContainer" > {titleContent && ( <div className= "title" > {titleContent} <div className= "titleCloseBtn" > <button>{closeIcon ?? 'X' }</button> </div> </div> )} <div className= "body" > {content} </div> <div className= "footer" > {actions && actions} </div> </div> </div> ); };
استفاده:
const handleCancel = () => { setIsOpen( false ); }; const handleContinue = () => { console .log( 'Continue action' ); }; <Modal open={isOpen} titleContent={<h2>Confirm Action</h2>} content={<p>Are you sure you want to proceed?</p>} closeIcon= "X" actions={ <div className= "custom-actions" > <button onClick={handleCancel}>Cancel</button> <button onClick={handleContinue}>Continue</button> </div> } />
در اینجا، ما اکنون دکمه ها را به عنوان یک ویژگی ارسال می کنیم. همچنین میتوانید مدال را طوری طراحی کنید که محتوا را بهعنوان یک مؤلفه فرزند ارسال کنید، اما این میتواند به هم ریخته شود، زیرا توسعهدهندگان ممکن است در نگاه اول این را بهعنوان انتقال محتوای مدال ببینند، نه فقط عناصر پاورقی.
با این حال، انجام این کار مزایا و معایبی دارد:
جوانب مثبت:
انعطافپذیری بیشتر : به شما امکان میدهد انواع عناصر را به بخش فوتر منتقل کنید. به عنوان مثال، چندین دکمه CTA (Call To Action)، پیوندها، یا هر چیزی که دوست دارید، با استایل سفارشی.
تفکیک نگرانی ها: مدال اکنون فقط مسئول رندر کردن ظرف (طرح، عنوان، محتوا و غیره) است. منطق اعمال (دکمهها) برای نمایش و رفتارهای آنها توسط مؤلفه والد که مودال را ارائه میکند، مدیریت میشود، که باعث میشود جزء مودال تمیزتر و قابل استفادهتر شود.
قابلیت استفاده مجدد بهبود یافته: شما می توانید هر JSX را به عنوان اکشن ارسال کنید و آن را برای موارد مختلف قابل استفاده کنید (به عنوان مثال، یک مدال با دکمه های ارسال فرم یا چندین گزینه). این رویکرد زمانی مفید است که مدالهایی دارید که به مجموعههای مختلفی از دکمهها یا تعاملات وابسته به منطق دیگر در مؤلفه والد/مدال نیاز دارند. منطق را می توان توسط یک تابع سازنده، یا در یک جزء بسته بندی دیگر که دکمه ها را در خود جای می دهد، مدیریت کرد.
معایب:
مسئولیت بیشتر بر روی مؤلفه والد: اکنون باید دکمهها را در هر نمونهای که از Modal
استفاده میکنید کنترل کنید. اگر مراقب نباشید ممکن است منجر به تکرار منطق دکمه (مانند handleCancel
و handleContinue
) در مکانهای مختلف شود.
استفاده کمی پیچیدهتر: رویکرد قبلی به شما امکان میداد که cancelFn
و primaryFn
را مستقیماً (اختیاری) ارسال کنید، که ممکن است برای موارد استفاده اکثریت/ساده آسانتر باشد. تصویب اقدامات در کودکی ممکن است نیاز به تنظیم بیشتری داشته باشد.
طرحبندی عملکرد ناسازگار : اگر به کد خود توجهی ندارید، ممکن است با قرار دادن دکمهها یا سبکهای متناقض در نمونههای مختلف مدال مواجه شوید. این را می توان با حصول اطمینان از اینکه همیشه در کودکی هنگام انجام اقدامات، نشانه گذاری یا سبک های ثابتی را پاس می کنید، مدیریت می شود، اما دوباره، ممکن است مدیریت آن دشوار شود.
نتیجه گیری
ساخت کامپوننت مودال قابل استفاده مجدد در React انعطاف پذیری و قابلیت استفاده مجدد را در سراسر برنامه شما ارائه می دهد. شما به راحتی می توانید مدال را با سناریوهای مختلف تطبیق دهید، خواه یک مدال تایید ساده باشد یا یک مدال ارسال فرم پیچیده تر.
با این حال، تعادل بین انعطاف پذیری و سادگی ضروری است - پیچیدگی بیش از حد ممکن است اجزای اصلی را با تکرار غیرضروری سنگین کند.
به طور کلی، این رویکرد کد شما را DRY نگه میدارد، قابلیت نگهداری را بهبود میبخشد و به شما امکان میدهد تا اجزای رابط کاربری مقیاسپذیر ایجاد کنید. با استفاده از این شیوهها و پیشرفتها، میتوانید مدالهای بسیار سازگاری بسازید که نیازهای مختلف را برآورده میکنند و هم تجربه توسعهدهنده و هم کیفیت محصول نهایی را بهبود میبخشند.
مثل همیشه، با خیال راحت من را دنبال کنید یا در Twitter/X تماس بگیرید.
ارسال نظر