نحوه ساخت یک مؤلفه کشویی پویا در React – الگوی مؤلفه ترکیبی React توضیح داده شده است
کرکرهها از زمان پیدایش آن بخشی از اینترنت بودهاند—آنها قهرمانی ناشناخته از تعامل با کاربر هستند که بیصدا اقدامات و تصمیمهای بیشماری را تنها با یک کلیک یا ضربه آسان میکنند.
احتمالاً امروز با یکی از آنها مواجه شدهاید، چه انتخاب یک دسته در فروشگاه اینترنتی مورد علاقهتان باشد یا انتخاب تاریخ تولد در فرم ثبتنام.
اما اگر به شما بگویم که یک عنصر مخفی وجود دارد که می تواند کشویی شما را از پیش پا افتاده به باشکوه ارتقا دهد، چه؟
به من بپیوندید تا اسرار الگوی اجزای مرکب را تشریح کنم و از توانایی های آن برای ساختن یک جزء کشویی پویا استفاده کنم.
پیش نیازها
مبانی HTML، CSS و Tailwind CSS
اصول React و React Hooks.
آنچه را پوشش خواهیم داد:
چگونه کامپوننت کشویی بسازیم
- روش واکنش عملکردی منظم
- روش الگوی اجزای مرکب
درک اجزای بازشو
اجزای کشویی نقش اساسی در طراحی رابط کاربری دارند و به عنوان منوهای تعاملی عمل می کنند که به کاربران امکان می دهد از فهرست ی از گزینه ها انتخاب کنند. به طور معمول، آنها از یک منطقه قابل کلیک تشکیل می شوند که پس از فعال سازی، فهرستی از انتخاب ها را برای کاربر به نمایش می گذارد تا از آن انتخاب کند.
عملکرد یک مؤلفه کشویی ساده است: وقتی کاربر با آن درگیر می شود - اغلب از طریق کلیک کردن یا ضربه زدن - منوی کشویی گسترش می یابد و گزینه های موجود را نشان می دهد.
متعاقباً، کاربر میتواند یکی از این گزینهها را انتخاب کند، که سپس در خود کشویی نشان داده میشود یا برای بهروزرسانی یک فیلد یا عنصر مرتبط در رابط استفاده میشود.
مؤلفههای کشویی روشی تمیز و کارآمد برای ارائه انتخابهای متنوع به کاربران ارائه میدهند و آنها را برای سناریوهایی که در آن چندین گزینه باید در دسترس باشند و در عین حال یک رابط مرتب حفظ میکنند، مناسب میسازد.
کرکره ها اهدافی مانند موارد زیر را نیز انجام می دهند:
کمک ناوبری : به عنوان کمک ناوبری عمل میکند، فهرستهای کشویی با ارائه منوها برای پرش به بخشها یا صفحات مختلف به کاربران کمک میکنند تا در وبسایتها حرکت کنند.
ورودیهای فرم : ورود دادهها را ساده میکند، فهرستهای کشویی گزینههای از پیش تعریفشدهای را برای انتخاب، مانند انتخاب کشور، تاریخ تولد، یا زبان ترجیحی در هنگام ثبت حساب، به کاربران ارائه میدهند.
فیلترها : در پلتفرمهای تجارت الکترونیک، فهرستهای کشویی به خریداران این امکان را میدهند تا با انتخاب گزینههایی مانند دستههای محصول، محدوده قیمت یا مارکها، نتایج جستجوی خود را اصلاح کنند.
انتخابگرهای منو : معمولاً در وبسایتهای رستوران مورد استفاده قرار میگیرند، منوها را نمایش میدهند یا به کاربران اجازه میدهند نوع غذا را انتخاب کنند، کاوش آسان و انتخاب گزینههای غذاخوری را تسهیل میکند.
ارائه داده ها : کرکره ها می توانند داده ها را به طور موثر سازماندهی و ارائه کنند و به کاربران این امکان را می دهند که اطلاعات را بر اساس معیارهایی مانند محدوده تاریخ، منطقه جغرافیایی یا دسته محصول در داشبورد یا ابزارهای تحلیلی فیلتر کنند.
نمونه ای از اجزای کشویی را می توان در اینجا مشاهده کرد:
یا در صفحه Semantic UI .
درک اجزای مرکب
الگوی اجزای مرکب مانند ساختن با بلوکهای لگو است: شما قطعات کوچکتری را برای ایجاد چیزی بزرگتر و پیچیدهتر جمعآوری میکنید. در React، این یک روش هوشمندانه برای طراحی اجزا از چندین بخش کوچکتر است که به طور یکپارچه با هم کار می کنند.
تصور کنید که در حال ساخت یک منوی کشویی هستید. به جای ایجاد یک جزء یکپارچه که همه چیز را کنترل می کند، آن را به قطعات کوچکتر و قابل استفاده مجدد تقسیم می کنید. ممکن است یک مؤلفه برای دکمه کشویی، دیگری برای فهرست گزینه ها، و دیگری برای مدیریت حالت و منطق تعامل داشته باشید.
اینجاست که جالب می شود: این اجزای کوچکتر از طریق یک زمینه مشترک ارتباط برقرار می کنند. متن مانند یک پیام رسان است که اطلاعات را از یک مؤلفه به مؤلفه دیگر بدون نیاز به انتقال آن در هر سطح از درخت مؤلفه منتقل می کند.
این ابزار قدرتمندی است که فرآیند به اشتراک گذاری داده ها را بین اجزاء، به خصوص زمانی که عمیقاً تو در تو هستند، ساده می کند.
حال، چرا این الگو اینقدر مفید است؟
اول از همه، خوانایی را بهبود می بخشد. با تقسیم یک جزء پیچیده به قطعات کوچکتر و متمرکزتر، درک و نگهداری کد آسان تر می شود. هر مؤلفه مسئولیت روشنی دارد که اشکال زدایی و به روز رسانی را آسان تر می کند.
ثانیا، اجزای ترکیبی قابلیت نگهداری را افزایش می دهند. از آنجایی که هر قطعه از کامپوننت وظیفه خاصی را انجام می دهد، ایجاد تغییرات یا گفت ن ویژگی های جدید بسیار ساده تر می شود. میتوانید یک قسمت از مؤلفه را بدون تأثیرگذاری بر سایر مؤلفهها تغییر دهید و خطر ایجاد اشکالات را کاهش دهید.
در نهایت، اجزای مرکب انعطاف پذیری زیادی را ارائه می دهند. شما میتوانید بخشهای مختلف را با هم ترکیب کنید تا نسخههای ویژهای از کامپوننت را بدون نیاز به بازنویسی هیچ کدی بسازید. این امر تنظیم قطعه را برای مقاصد مختلف و الزامات طراحی آسان تر می کند.
پس ، در حالی که ایده استفاده از زمینه برای ساخت مؤلفههای رابط کاربری ممکن است در ابتدا غیرعادی به نظر برسد، این یک راه هوشمندانه برای ایجاد مؤلفههای پویا و قابل استفاده مجدد است که توسعهدهندگان را قادر میسازد تا تجربیات کاربری استثنایی ایجاد کنند.
در بخش بعدی، عمیقتر به نحوه استفاده از زمینه برای زنده کردن اجزای ترکیبی خواهیم پرداخت.
چگونه کامپوننت کشویی بسازیم
من یک مخزن GitHub با فایل های شروع کننده برای سرعت بخشیدن به کار آماده کرده ام. به سادگی این مخزن را شبیه سازی کنید و وابستگی ها را نصب کنید.
در این بخش، یک جزء کشویی با استفاده از React عملکردی معمولی می سازیم، سپس آن را با الگوی CC مقایسه می کنیم تا تفاوت را به طور کامل درک کنید. PS: شما الگوی اجزای مرکب را میخواهید. 😁
روش واکنش عملکردی منظم
ما با ایجاد ساختار اصلی جزء کشویی خود شروع می کنیم. این شامل تنظیم محفظه کشویی اصلی، دکمه فعال کردن کشویی و فهرست گزینه ها است.
const Dropdown = () => { return ( <div> <label className="mt-4">Assign user(s) to as task:</label> <button className=" px-4 w-full py-2 flex items-center justify-between rounded border border-[#828FA340] hover:border-primary cursor-pointer relative "> <span className="block"> <FiChevronDown color="#635FC7" size={24} /> </span> </button> </div> ); };
که می دهد:
سپس آرایه کاربران را به منوی کشویی ارسال کنید تا فهرست ی از کاربران ایجاد شود.
const Dropdown = ({ usersArray }) => { return ( <div> <label className="mt-4">Assign user(s) to as task:</label> <button className=" px-4 w-full py-2 flex items-center justify-between rounded border border-[#828FA340] hover:border-primary cursor-pointer relative "> <span className="block"> <FiChevronDown color="#635FC7" size={24} /> </span> { <div className="absolute bottom-full translate-x-9 left-full translate-y-full rounded bg-[#20212c] w-max"> <ul className="flex flex-col p-2"> {usersArray.map((user) => ( <li key={user.id} className={`flex items-center gap-2 p-4 hover:bg-[#2b2c37] rounded transition-all duration-200 `}> <img className="w-6 h-6 " src={user.imgUrl} alt={`${user.name} image`} /> <span>{user.name}</span> </li> ))} </ul> </div> } </button> </div> ); };
که می دهد:
در حال حاضر، فهرست کشویی شما به طور پیش فرض نشان داده می شود. برای گفت ن رفتار جابجایی، یک حالت برای نمایان بودن آن ایجاد کنید.
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
سپس هر دو را به عنوان props به مؤلفه Dropdown
منتقل کنید.
<Dropdown usersArray={usersArray} isDropdownOpen={isDropdownOpen} setIsDropdownOpen={setIsDropdownOpen} />
قبل از اینکه نتیجه را مشاهده کنید، یک تابع جابجایی که حالت کشویی را به true تغییر می دهد به دکمه کشویی متصل کنید.
const toggleDropdown = () => { setIsDropdownOpen(true); };
اکنون جزء کشویی شما باید به شکل زیر باشد:
const Dropdown = ({ usersArray, setIsDropdownOpen, isDropdownOpen }) => { const toggleDropdown = () => { setIsDropdownOpen(true); }; return ( <div> <label className="mt-4">Assign user(s) to as task:</label> <button className=" px-4 w-full py-2 flex items-center justify-between rounded border border-[#828FA340] hover:border-primary cursor-pointer relative " // Function to show the dropdown on click onClick={toggleDropdown}> <span className="block"> <FiChevronDown color="#635FC7" size={24} /> </span> // Conditionally rendering your dropdown list {isDropdownOpen && ( <div className="absolute bottom-full translate-x-9 left-full translate-y-full rounded bg-[#20212c] w-max"> <ul className="flex flex-col p-2"> {usersArray.map((user) => ( <li key={user.id} className={`flex items-center gap-2 p-4 hover:bg-[#2b2c37] rounded transition-all duration-200 `}> <img className="w-6 h-6 " src={user.imgUrl} alt={`${user.name} image`} /> <span>{user.name}</span> </li> ))} </ul> </div> )} </button> </div> ); };
اکنون فهرست کشویی شما به این صورت عمل می کند:
می دانم که متوجه شده اید کشویی شما فقط باز می شود، اما بسته نمی شود. نگران نباشید، ما بعداً آن را با روشی بسیار تمیزتر برطرف خواهیم کرد. 😉
در مرحله بعد، بیایید راهی برای اختصاص دادن کاربران به کار ایجاد کنیم. با ایجاد وضعیتی برای ذخیره کاربران اختصاص داده شده در مؤلفه App
شروع کنید.
const [assignedList, setAssignedList] = useState([]);
سپس مقادیر را به عنوان props به مؤلفه Dropdown
منتقل کنید.
<Dropdown usersArray={usersArray} isDropdownOpen={isDropdownOpen} setIsDropdownOpen={setIsDropdownOpen} assignedList={assignedList} setAssignedList={setAssignedList} />
برای اختصاص دادن کاربران به این کار، یک تابع کنترل کننده ایجاد کنید که ابتدا تحلیل می کند کاربری که می خواهید اضافه کنید قبلاً در آرایه است یا خیر، اگر نیست آنها را اضافه می کند و اگر هستند حذف می کند.
function handleAssign(user) { setAssignedList((prevList) => { // Check if the user already exists in the list if (prevList.includes(user)) { // If user exists, remove it from the list const updatedList = prevList.filter((item) => item !== user); return updatedList; } else { // If user doesn't exist, add it to the list return [...prevList, user]; } }); }
برای تایید کارکرد این تابع، از آرایه assignedList
برای اضافه کردن نماد تحلیل به هر کاربر اختصاص داده شده استفاده کنید.
<ul className="flex flex-col p-2"> {usersArray.map((user) => ( <li key={user.id} className={`flex items-center gap-2 p-4 hover:bg-[#2b2c37] rounded transition-all duration-200 `} onClick={() => handleAssign(user)} > {assignedList.includes(user) && <FiCheck />} <img className="w-6 h-6 " src={user.imgUrl} alt={`${user.name} image`} /> <span>{user.name}</span> </li> ))} </ul>
با این تغییر، منوی کشویی باید با کلیک هر کاربر، کاربران را اختصاص داده و لغو اختصاص دهد.
برای بهبود رابط کاربری، اجازه دهید یک مؤلفه ایجاد کنیم که همه کاربران اختصاص داده شده را نشان دهد.
یک جزء AssignedList
ایجاد کنید و در حالت های مربوطه آن را ارسال کنید.
<AssignedList assignedList={assignedList} setAssignedList={setAssignedList} />
سپس از آرایه اختصاص داده شده برای ایجاد JSX استفاده کنید.
function AssignedList({ assignedList, setAssignedList }) { return ( <div className="mt-4 p-2 shadow-sm bg-[#828fa318] rounded"> <h2 className="px-2 my-3 font-bold">Assigned list:</h2> <div className="flex flex-wrap gap-4 "> {assignedList?.map((user, index) => ( <div key={user.id} className="flex items-center gap-1 w-[47.5%] p-2 hover:bg-[#20212c] rounded transition-all duration-200"> <span>{index + 1}.</span> <img className="w-6 h-6 " src={user.imgUrl} alt={`${user.name} image`} /> <span>{user.name}</span> <span className="ml-auto cursor-pointer p-1 hover:bg-[#2b2c37] rounded-full"> <FaXmark /> </span> </div> ))} </div> </div> ); }
اکنون آزمایش مؤلفه شما نتیجه می دهد:
یکی از آخرین اقدامات استفاده از نماد x برای حذف یک کاربر از تکلیف است.
این را می توان با استفاده از تابع setAssigned
برای فیلتر کردن کاربر بر اساس id
آنها انجام داد.
function handleRemove(id) { setAssignedList((assignedList) => assignedList.filter((user) => user.id !== id) ); }
سپس شناسه کاربری را از حلقه ارسال کنید.
function AssignedList({ assignedList, setAssignedList }) { function handleRemove(id) { setAssignedList((assignedList) => assignedList.filter((user) => user.id !== id) ); } return ( <div className="mt-4 p-2 shadow-sm bg-[#828fa318] rounded"> <h2 className="px-2 my-3 font-bold">Assigned list:</h2> <div className="flex flex-wrap gap-4 "> {assignedList?.map((user, index) => ( <div key={user.id} className="flex items-center gap-1 w-[47.5%] p-2 hover:bg-[#20212c] rounded transition-all duration-200" onClick={() => handleRemove(user.id)}> <span>{index + 1}.</span> <img className="w-6 h-6 " src={user.imgUrl} alt={`${user.name} image`} /> <span>{user.name}</span> <span className="ml-auto cursor-pointer p-1 hover:bg-[#2b2c37] rounded-full"> <FaXmark /> </span> </div> ))} </div> </div> ); }
این می دهد:
نکته نهایی دیگر بستن فهرست کشویی در برخی از تعاملات کاربر است.
برای شروع، من دوست دارم از یک قلاب قابل استفاده مجدد برای این کار استفاده کنم، که یک عنصر مرجع و یک تابع را می گیرد تا زمانی که هر ناحیه خارج از عنصر هدف من کلیک می شود، شلیک می کند.
import { useEffect } from "react"; const useClickOutside = (ref, handler) => { // console.log(handler, ref); useEffect(() => { const listener = (event) => { // Do nothing if clicking ref's element or descendent elements if (!ref.current || ref.current.contains(event.target)) { return; } handler(event); }; document.addEventListener("mousedown", listener); document.addEventListener("touchstart", listener); return () => { document.removeEventListener("mousedown", listener); document.removeEventListener("touchstart", listener); }; }, [ref, handler]); }; export default useClickOutside;
سپس در جزء App
ما، با استفاده از قلاب useRef
برای انتخاب یک عنصر، یک ref ایجاد کنید.
const dropdownContainerRef = useRef(null);
سپس آن را به عنصر دلخواه خود اختصاص دهید.
export default function App() { const [isDropdownOpen, setIsDropdownOpen] = useState(false); const [assignedList, setAssignedList] = useState([]); const dropdownContainerRef = useRef(null); return ( <div className="bg-[#2b2c37] h-[100dvh] text-white flex p-20 gap-4 items-center flex-col"> <div className=" w-[400px] " ref={dropdownContainerRef}> <h1 className="text-2xl ">Regular Functional React Pattern</h1> <Dropdown usersArray={usersArray} isDropdownOpen={isDropdownOpen} setIsDropdownOpen={setIsDropdownOpen} assignedList={assignedList} setAssignedList={setAssignedList} /> <AssignedList assignedList={assignedList} setAssignedList={setAssignedList} /> </div> </div> ); }
در نهایت، قلاب و پاس خود را در عنصر مرجع و تابع کنترل کننده تابع برای بستن بازشو وارد کنید.
useClickOutside(dropdownContainerRef, () => { setIsDropdownOpen(false); });
آزمایش کامپوننت شما اکنون به شما می دهد:
یا با استفاده از یک دکمه از پیش تعریف شده در بازشو.
<button className="px-4 w-full py-2 flex items-center justify-between rounded border border-[#828FA340] hover:border-primary cursor-pointer relative" onClick={toggleDropdown} > <span className="block"> <FiChevronDown color="#635FC7" size={24} /> </span> {isDropdownOpen && ( <div className="absolute bottom-full translate-x-9 left-full translate-y-full rounded bg-[#20212c] w-max"> {/* Close button */} <div className="absolute top-0 right-0 flex items-center justify-center -translate-y-full gap-2 bg-[#C0392B] px-2 py-1 rounded-t" onClick={(e) => { e.stopPropagation(); setIsDropdownOpen(false); console.log(isDropdownOpen); }} > <span>Close</span> <span> <FaXmark size={20} /> </span> </div> <ul className="flex flex-col p-2"> {usersArray.map((user) => ( <li key={user.id} className={`flex items-center gap-2 p-4 hover:bg-[#2b2c37] rounded transition-all duration-200`} onClick={() => handleAssign(user)} > {assignedList.includes(user) && <FiCheck />} <img className="w-6 h-6" src={user.imgUrl} alt={`${user.name} image`} /> <span>{user.name}</span> </li> ))} </ul> </div> )} </button>
تغییر نهایی یک تغییر نظری است زیرا اگر در حال حاضر هیچ کاربری به این کار اختصاص داده نشده باشد ترجیح میدهم چیز دیگری را نشان دهم.
{assignedList.length === 0 ? ( <p className="mt-4 p-2 shadow-sm bg-[#828fa318] rounded"> No users assigned to the task yet. </p> ) : ( <AssignedList assignedList={assignedList} setAssignedList={setAssignedList} /> )}
این UI را به این موارد می رساند:
روش الگوی اجزای مرکب
حالا برای رویداد اصلی. با ایجاد زمینه ای که کل مؤلفه را در بر می گیرد، شروع کنید.
const UserAssignContext = createContext();
سپس تمام دادهها و توابع لازم را که فهرست کشویی و اجزای آن به آن نیاز دارند جمعآوری میکنیم. این شامل مواردی مانند فهرست کاربران اختصاص داده شده، عملکردی برای به روز رسانی آن فهرست و باز بودن یا نبودن فهرست کشویی است.
پس از آن، شما آن مقادیر را به تمام اجزای فرزند آن ارائه می دهید.
const UserAssignDropdown = ({ children, assignedList, setAssignedList, users, }) => { const UserAssignDropdownRef = useRef(null); const [isDropdownOpen, setIsDropdownOpen] = useState(false); return ( <UserAssignContext.Provider value={{ assignedList, users, UserAssignDropdownRef, isDropdownOpen, setIsDropdownOpen, setAssignedList, }}> <div ref={UserAssignDropdownRef}>{children}</div> </UserAssignContext.Provider> ); };
با تنظیم زمینه ما، زمان آن فرا رسیده است که اجزای جداگانهای را که فهرست کشویی ما را تشکیل میدهند، بسازیم. هر جزء برای دسترسی و دستکاری داده ها و توابع لازم با زمینه تعامل خواهد داشت.
با کپی کردن هر سبک از اجزایی که به تازگی ساخته ایم شروع کنید.
جزء سرصفحه
این جزء ثابت باقی می ماند.
const Header = () => { return <label className="mt-4 mb-2 text-sm">Assign task to:</label>; };
جزء نزدیک
این کامپوننت تابعی را برای جابجایی کشویی از متن به دست می آورد.
const Close = () => { const { setIsDropdownOpen } = useContext(UserAssignContext); return ( <div className="absolute top-0 right-0 flex items-center justify-center -translate-y-full gap-2 bg-[#C0392B] px-2 py-1 rounded-t" onClick={(e) => { e.stopPropagation(); setIsDropdownOpen(false); }}> <span>Close</span> <span> <FaXmark size={20} /> </span> </div> ); };
جزء فهرست تعیین شده
این کامپوننت فهرست کاربران اختصاص داده شده را نمایش می دهد و همچنین کاربران را از فهرست حذف می کند.
const AssignedList = () => { const { assignedList, setAssignedList } = useContext(UserAssignContext); function handleRemove(id) { setAssignedList((assignedList) => assignedList.filter((user) => user.id !== id) ); } if (assignedList.length === 0) return ( <p className="mt-4 p-2 shadow-sm bg-[#828fa318] rounded"> No users assigned to the task yet. </p> ); return ( <div className="mt-4 p-2 shadow-sm bg-[#828fa318] rounded"> <h2 className="px-2 my-3 font-bold">Assigned list:</h2> <div className="flex flex-wrap gap-4 "> {assignedList?.map((user, index) => ( <div key={user.id} className="flex items-center gap-1 w-[47.5%] p-2 hover:bg-[#20212c] rounded transition-all duration-200" onClick={() => handleRemove(user.id)}> <span>{index + 1}.</span> <img className="w-6 h-6 " src={user.imgUrl} alt={`${user.name} image`} /> <span>{user.name}</span> <span className="ml-auto cursor-pointer p-1 hover:bg-[#2b2c37] rounded-full"> <FaXmark /> </span> </div> ))} </div> </div> ); };
جزء آیتم
این جزء هر کاربر و قابلیت گفت ن و حذف کاربران از فهرست اختصاص داده شده را نشان می دهد.
const Item = ({ user }) => { const { assignedList, setAssignedList } = useContext(UserAssignContext); function handleAssign(user) { setAssignedList((prevList) => { // Check if the user already exists in the list if (prevList.includes(user)) { // If user exists, remove it from the list const updatedList = prevList.filter((item) => item !== user); return updatedList; } else { // If user doesn't exist, add it to the list return [...prevList, user]; } }); } return ( <li key={user.id} className={`flex items-center gap-2 p-4 hover:bg-[#2b2c37] rounded transition-all duration-200 `} onClick={() => handleAssign(user)}> {assignedList.includes(user) && <FiCheck />} <img className="w-6 h-6 " src={user.imgUrl} alt={`${user.name} image`} /> <span>{user.name}</span> </li> ); };
جزء دکمه
این کامپوننت نمایش مولفه List
(کرکره شناور) را کنترل می کند.
const Button = () => { const { setIsDropdownOpen } = useContext(UserAssignContext); return ( <button className=" px-4 py-2 flex items-center justify-between w-full rounded border border-[#828FA340] hover:border-primary cursor-pointer relative " onClick={() => setIsDropdownOpen(true)}> <span className="block"> <FiChevronDown color="#635FC7" size={24} /> </span> <UserAssignDropdown.List /> </button> ); };
برای ترکیب این جزء به یک جزء ترکیبی منفرد (جزء مرکب)، هر جزء را به والد اختصاص میدهید.
UserAssignDropdown.List = ListContainer; UserAssignDropdown.Item = Item; UserAssignDropdown.Header = Header; UserAssignDropdown.Button = Button; UserAssignDropdown.AssignedList = AssignedList; UserAssignDropdown.Close = Close;
در مرحله بعد، جزء ترکیبی خود را در کامپوننت App
خود به عنوان کامپوننت wrapper وارد کنید و در حالت های مناسب پاس کنید.
export default function App() { const [assignedList, setAssignedList] = useState([]); return ( <div className="bg-[#2b2c37] h-[100dvh] text-white flex p-20 gap-4 items-center flex-col"> <div className=" w-[400px] "> <h1 className="text-2xl ">Compound Component Pattern</h1> <UserAssignDropdown assignedList={assignedList} setAssignedList={setAssignedList} users={usersArray}></UserAssignDropdown> </div> </div> ); }
سپس در لفاف، فرزندان مناسب را رندر کنید.
export default function App() { const [assignedList, setAssignedList] = useState([]); return ( <div className="bg-[#2b2c37] h-[100dvh] text-white flex p-20 gap-4 items-center flex-col"> <div className=" w-[400px] "> <h1 className="text-2xl ">Compound Component Pattern</h1> <UserAssignDropdown assignedList={assignedList} setAssignedList={setAssignedList} users={usersArray}> <UserAssignDropdown.Header /> <UserAssignDropdown.Button /> <UserAssignDropdown.AssignedList /> </UserAssignDropdown> </div> </div> ); }
در نهایت، از قلاب سفارشی که قبلا ایجاد کردیم استفاده کنید تا وقتی خارج از کامپوننت کلیک میکنید، فهرست بازشو را ببندید.
const UserAssignContext = createContext(); const UserAssignDropdown = ({ children, assignedList, setAssignedList, users, }) => { const UserAssignDropdownRef = useRef(null); const [isDropdownOpen, setIsDropdownOpen] = useState(false); useClickOutside(UserAssignDropdownRef, () => { setIsDropdownOpen(false); }); return ( <UserAssignContext.Provider value={{ assignedList, users, UserAssignDropdownRef, isDropdownOpen, setIsDropdownOpen, setAssignedList, }}> <div ref={UserAssignDropdownRef}>{children}</div> </UserAssignContext.Provider> ); };
و با آن، کامپوننت شما یکسان کار می کند!
اما چرا اینجا توقف کنید؟
با این الگو، تغییر ظاهر کامپوننت به آسانی تغییر ترتیبی است که آنها را در والد آنها رندر می کنید. به عنوان مثال، اگر ابتدا دکمه را می خواستید، به سادگی ترتیب در بسته بندی اصلی را تغییر دهید.
<UserAssignDropdown assignedList={assignedList} setAssignedList={setAssignedList} users={usersArray} > <UserAssignDropdown.Button /> <UserAssignDropdown.Header /> <UserAssignDropdown.AssignedList /> </UserAssignDropdown>
و UI بر این اساس پاسخ می دهد.
این مولفه همچنین به اندازه کافی انعطاف پذیر است تا طرح بندی عناصر را از طریق props تغییر دهد.
فقط با دادن لوازم سبک از طریق والدین:
<UserAssignDropdown assignedList={assignedList} setAssignedList={setAssignedList} users={usersArray} > <UserAssignDropdown.Header /> <UserAssignDropdown.Button listStyles={"!-left-5 !-translate-x-full bg-[#605e80] text-white border"} /> <UserAssignDropdown.AssignedList /> </UserAssignDropdown>
و دریافت آن وسایل در کودک:
const Button = ({ listStyles }) => { const { setIsDropdownOpen, UserAssignDropdownRef } = useContext(UserAssignContext); return ( <button className=" px-4 py-2 flex items-center justify-between w-full rounded border border-[#828FA340] hover:border-primary cursor-pointer relative " ref={UserAssignDropdownRef} onClick={() => setIsDropdownOpen(true)}> <span className="block"> <FiChevronDown color="#635FC7" size={24} /> </span> <UserAssignDropdown.List listStyles={listStyles} /> </button> ); }; const ListContainer = ({ listStyles }) => { const { users, isDropdownOpen } = useContext(UserAssignContext); return ( isDropdownOpen && ( <ul className={`absolute bottom-full translate-x-9 left-full translate-y-full rounded bg-[#20212c] w-max ${listStyles}`}> <UserAssignDropdown.Close /> <div className="flex flex-col p-2"> {users?.map((user, index) => ( <UserAssignDropdown.Item key={index} user={user} /> ))} </div> </ul> ) ); };
شما به راحتی می توانید ظاهر کامپوننت را تغییر دهید.
مقایسه بین روش Regular و Compound Component
خوب، بیایید یک قدم به عقب برگردیم و دو رویکردی را که اخیراً تحلیل کردیم، مقایسه کنیم.
سادگی و سازماندهی
روش معمولی : آن را مانند پختن یک کیک در یک کاسه بزرگ تصور کنید. با روش معمولی، میتوانیم یک مؤلفه واحد ایجاد کنیم که مسئول همه چیز در منوی کشویی است - دکمه، فهرست و همه مواد تشکیل دهنده. مثل این است که یک کارت دستور پخت بزرگ داشته باشید که تمام مراحل آن به هم ریخته باشد. این کار کار را انجام می دهد، اما ممکن است کمی کثیف و سخت باشد، به خصوص زمانی که می خواهید فقط یک قسمت از دستور غذا را تغییر دهید.
روش اجزای مرکب : حالا تصور کنید برای هر ماده کاسه های مختلفی داریم، یک کاسه جداگانه برای آرد، دیگری برای شکر و غیره. این الگوی اجزای مرکب است. هر قسمت از کرکره فضای خاص خود را برای درخشش دارد. این مانند سازماندهی آشپزخانه شماست – هر چیزی جای خود را دارد. این امر درک و اصلاح آن را آسان تر می کند. آیا نیاز به تغییر آرد دارید؟ شما فقط می دانید به کجا نگاه کنید.
انعطاف پذیری و سفارشی سازی
روش معمولی : با رویکرد تک کاسهای ما، ایجاد تغییرات در بخشهای خاصی از فهرست کشویی میتواند کمی شبیه تلاش برای تعویض مواد در آن مخلوط کیک بزرگ باشد. مطمئنا، شما می توانید آن را انجام دهید، اما همیشه آسان نیست. طعم متفاوت کیک می خواهید؟ ممکن است لازم باشد کل کاسه را حفر کنید تا کجا آن را اضافه کنید.
روش اجزای مرکب : با الگوی اجزای ترکیبی، مانند این است که برای هر طعم ظروف جداگانه ای داشته باشید. آیا نیاز به اضافه کردن چیپس شکلات دارید؟ فقط ظرف شکلات را بردارید و بپاشید. هر جزء کار خود را دارد و سفارشی کردن آن را سادهتر میکند. آیا می خواهید رنگ دکمه را تغییر دهید؟ مشکلی نیست، همان جا در ظرفش است.
استفاده مجدد و نگهداری
روش معمولی : وقتی دستور پخت شما در یک کاسه مخلوط می شود، استفاده مجدد از قسمت هایی از آن برای یک غذای دیگر دشوار است. بهعلاوه، با شلوغتر شدن آشپزخانهتان، آشفتگی همهچیز آسانتر و پیگیری آنها سخت میشود. ممکن است هر بار که می خواهید چیز جدیدی درست کنید، دستور غذا را بازنویسی می کنید.
روش اجزای مرکب : با الگوی اجزای مرکب، مانند این است که مجموعه ای از ابزارهای قابل استفاده مجدد در آشپزخانه خود داشته باشید. آیا نیاز به تهیه یک کیک متفاوت دارید؟ فقط ابزار مورد نیاز خود را بردارید و پخت را انجام دهید. هر جزء مانند یک ابزار تخصصی است – استفاده مجدد و نگهداری آن آسان است. و هنگامی که آشپزخانه شما سازماندهی شده است، نسیمی است که چیز جدیدی را تولید کنید.
اطلاعات تکمیلی
در اینجا پیوندهایی به تمام منابعی که ممکن است از این مقاله نیاز داشته باشید وجود دارد.
نتیجه
در پایان، هر دو روش جای خود را در آشپزخانه دارند - منظورم این است که در کد شما. روش معمولی مانند کاسه همزن قدیمی شما است - قابل اعتماد و آشنا، اما شاید برای هر دستور غذا کارآمدترین روش نباشد.
اجزای ترکیبی Pattern مانند یک آشپزخانه منظم است که همه چیز در جای خود و آماده کار است. ممکن است راه اندازی کمی بیشتر طول بکشد، اما می تواند زندگی شما را در دراز مدت بسیار آسان تر کند. پس ، بسته به آنچه که در حال پختن هستید، روشی را انتخاب کنید که مطابق با سلیقه شما باشد – و کدنویسی شاد! 🍰🎨
اطلاعات تماس
می خواهید به من وصل شوید یا با من تماس بگیرید؟ در صورت تمایل به من در مورد موارد زیر ضربه بزنید:
توییتر / X: @jajadavid8
لینکدین: دیوید جاجا
ایمیل: Jajadavidjid@gmail.com
ارسال نظر