متن خبر

نحوه ساخت یک مؤلفه کشویی پویا در React – الگوی مؤلفه ترکیبی React توضیح داده شده است

نحوه ساخت یک مؤلفه کشویی پویا در React – الگوی مؤلفه ترکیبی React توضیح داده شده است

شناسهٔ خبر: 465223 -




کرکره‌ها از زمان پیدایش آن بخشی از اینترنت بوده‌اند—آنها قهرمانی ناشناخته از تعامل با کاربر هستند که بی‌صدا اقدامات و تصمیم‌های بی‌شماری را تنها با یک کلیک یا ضربه آسان می‌کنند.

احتمالاً امروز با یکی از آن‌ها مواجه شده‌اید، چه انتخاب یک دسته در فروشگاه اینترنتی مورد علاقه‌تان باشد یا انتخاب تاریخ تولد در فرم ثبت‌نام.

اما اگر به شما بگویم که یک عنصر مخفی وجود دارد که می تواند کشویی شما را از پیش پا افتاده به باشکوه ارتقا دهد، چه؟

به من بپیوندید تا اسرار الگوی اجزای مرکب را تشریح کنم و از توانایی های آن برای ساختن یک جزء کشویی پویا استفاده کنم.

پیش نیازها

مبانی HTML، CSS و Tailwind CSS

اصول React و React Hooks.

آنچه را پوشش خواهیم داد:

    درک اجزای بازشو

    درک اجزای مرکب

    چگونه کامپوننت کشویی بسازیم
    - روش واکنش عملکردی منظم
    - روش الگوی اجزای مرکب

    مقایسه بین روش کامپوننت معمولی و مرکب

    نتیجه

درک اجزای بازشو

اجزای کشویی نقش اساسی در طراحی رابط کاربری دارند و به عنوان منوهای تعاملی عمل می کنند که به کاربران امکان می دهد از فهرست ی از گزینه ها انتخاب کنند. به طور معمول، آنها از یک منطقه قابل کلیک تشکیل می شوند که پس از فعال سازی، فهرستی از انتخاب ها را برای کاربر به نمایش می گذارد تا از آن انتخاب کند.

عملکرد یک مؤلفه کشویی ساده است: وقتی کاربر با آن درگیر می شود - اغلب از طریق کلیک کردن یا ضربه زدن - منوی کشویی گسترش می یابد و گزینه های موجود را نشان می دهد.

متعاقباً، کاربر می‌تواند یکی از این گزینه‌ها را انتخاب کند، که سپس در خود کشویی نشان داده می‌شود یا برای به‌روزرسانی یک فیلد یا عنصر مرتبط در رابط استفاده می‌شود.

مؤلفه‌های کشویی روشی تمیز و کارآمد برای ارائه انتخاب‌های متنوع به کاربران ارائه می‌دهند و آنها را برای سناریوهایی که در آن چندین گزینه باید در دسترس باشند و در عین حال یک رابط مرتب حفظ می‌کنند، مناسب می‌سازد.

کرکره ها اهدافی مانند موارد زیر را نیز انجام می دهند:

کمک ناوبری : به عنوان کمک ناوبری عمل می‌کند، فهرست‌های کشویی با ارائه منوها برای پرش به بخش‌ها یا صفحات مختلف به کاربران کمک می‌کنند تا در وب‌سایت‌ها حرکت کنند.

ورودی‌های فرم : ورود داده‌ها را ساده می‌کند، فهرست‌های کشویی گزینه‌های از پیش تعریف‌شده‌ای را برای انتخاب، مانند انتخاب کشور، تاریخ تولد، یا زبان ترجیحی در هنگام ثبت حساب، به کاربران ارائه می‌دهند.

فیلترها : در پلتفرم‌های تجارت الکترونیک، فهرست‌های کشویی به خریداران این امکان را می‌دهند تا با انتخاب گزینه‌هایی مانند دسته‌های محصول، محدوده قیمت یا مارک‌ها، نتایج جستجوی خود را اصلاح کنند.

انتخابگرهای منو : معمولاً در وب‌سایت‌های رستوران مورد استفاده قرار می‌گیرند، منوها را نمایش می‌دهند یا به کاربران اجازه می‌دهند نوع غذا را انتخاب کنند، کاوش آسان و انتخاب گزینه‌های غذاخوری را تسهیل می‌کند.

ارائه داده ها : کرکره ها می توانند داده ها را به طور موثر سازماندهی و ارائه کنند و به کاربران این امکان را می دهند که اطلاعات را بر اساس معیارهایی مانند محدوده تاریخ، منطقه جغرافیایی یا دسته محصول در داشبورد یا ابزارهای تحلیلی فیلتر کنند.

نمونه ای از اجزای کشویی را می توان در اینجا مشاهده کرد:

01-نمایش-کشویی-دمو
نمایش نسخه ی نمایشی کشویی

یا در صفحه Semantic UI .

درک اجزای مرکب

الگوی اجزای مرکب مانند ساختن با بلوک‌های لگو است: شما قطعات کوچک‌تری را برای ایجاد چیزی بزرگ‌تر و پیچیده‌تر جمع‌آوری می‌کنید. در React، این یک روش هوشمندانه برای طراحی اجزا از چندین بخش کوچکتر است که به طور یکپارچه با هم کار می کنند.

تصور کنید که در حال ساخت یک منوی کشویی هستید. به جای ایجاد یک جزء یکپارچه که همه چیز را کنترل می کند، آن را به قطعات کوچکتر و قابل استفاده مجدد تقسیم می کنید. ممکن است یک مؤلفه برای دکمه کشویی، دیگری برای فهرست گزینه ها، و دیگری برای مدیریت حالت و منطق تعامل داشته باشید.

01-ترکیب-کامپوننت-تصویرسازی
تصویر کامپوننت مرکب

اینجاست که جالب می شود: این اجزای کوچکتر از طریق یک زمینه مشترک ارتباط برقرار می کنند. متن مانند یک پیام رسان است که اطلاعات را از یک مؤلفه به مؤلفه دیگر بدون نیاز به انتقال آن در هر سطح از درخت مؤلفه منتقل می کند.

این ابزار قدرتمندی است که فرآیند به اشتراک گذاری داده ها را بین اجزاء، به خصوص زمانی که عمیقاً تو در تو هستند، ساده می کند.

حال، چرا این الگو اینقدر مفید است؟

اول از همه، خوانایی را بهبود می بخشد. با تقسیم یک جزء پیچیده به قطعات کوچکتر و متمرکزتر، درک و نگهداری کد آسان تر می شود. هر مؤلفه مسئولیت روشنی دارد که اشکال زدایی و به روز رسانی را آسان تر می کند.

ثانیا، اجزای ترکیبی قابلیت نگهداری را افزایش می دهند. از آنجایی که هر قطعه از کامپوننت وظیفه خاصی را انجام می دهد، ایجاد تغییرات یا گفت ن ویژگی های جدید بسیار ساده تر می شود. می‌توانید یک قسمت از مؤلفه را بدون تأثیرگذاری بر سایر مؤلفه‌ها تغییر دهید و خطر ایجاد اشکالات را کاهش دهید.

در نهایت، اجزای مرکب انعطاف پذیری زیادی را ارائه می دهند. شما می‌توانید بخش‌های مختلف را با هم ترکیب کنید تا نسخه‌های ویژه‌ای از کامپوننت را بدون نیاز به بازنویسی هیچ کدی بسازید. این امر تنظیم قطعه را برای مقاصد مختلف و الزامات طراحی آسان تر می کند.

پس ، در حالی که ایده استفاده از زمینه برای ساخت مؤلفه‌های رابط کاربری ممکن است در ابتدا غیرعادی به نظر برسد، این یک راه هوشمندانه برای ایجاد مؤلفه‌های پویا و قابل استفاده مجدد است که توسعه‌دهندگان را قادر می‌سازد تا تجربیات کاربری استثنایی ایجاد کنند.

در بخش بعدی، عمیق‌تر به نحوه استفاده از زمینه برای زنده کردن اجزای ترکیبی خواهیم پرداخت.

چگونه کامپوننت کشویی بسازیم

من یک مخزن GitHub با فایل های شروع کننده برای سرعت بخشیدن به کار آماده کرده ام. به سادگی این مخزن را شبیه سازی کنید و وابستگی ها را نصب کنید.

در این بخش، یک جزء کشویی با استفاده از React عملکردی معمولی می سازیم، سپس آن را با الگوی CC مقایسه می کنیم تا تفاوت را به طور کامل درک کنید. PS: شما الگوی اجزای مرکب را می‌خواهید. 😁

02-Oh-fo-sho-meme
گیف اوه فو شو اسنوپ داگ

روش واکنش عملکردی منظم

ما با ایجاد ساختار اصلی جزء کشویی خود شروع می کنیم. این شامل تنظیم محفظه کشویی اصلی، دکمه فعال کردن کشویی و فهرست گزینه ها است.

 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> ); };

که می دهد:

02-دکمه کشویی ارائه شده است
دکمه کشویی ارائه شده است

سپس آرایه کاربران را به منوی کشویی ارسال کنید تا فهرست ی از کاربران ایجاد شود.

 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> ); };

که می دهد:

03-Dropdown-list-rendered
فهرست کشویی ارائه شد

در حال حاضر، فهرست کشویی شما به طور پیش فرض نشان داده می شود. برای گفت ن رفتار جابجایی، یک حالت برای نمایان بودن آن ایجاد کنید.

 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> ); };

اکنون فهرست کشویی شما به این صورت عمل می کند:

03-Dropdown-with-list-conditionally-rendering
کشویی با ارائه فهرست به صورت مشروط

می دانم که متوجه شده اید کشویی شما فقط باز می شود، اما بسته نمی شود. نگران نباشید، ما بعداً آن را با روشی بسیار تمیزتر برطرف خواهیم کرد. 😉

04-به فرآیند اعتماد کنید
به فرآیند اعتماد کنید

در مرحله بعد، بیایید راهی برای اختصاص دادن کاربران به کار ایجاد کنیم. با ایجاد وضعیتی برای ذخیره کاربران اختصاص داده شده در مؤلفه 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>

با این تغییر، منوی کشویی باید با کلیک هر کاربر، کاربران را اختصاص داده و لغو اختصاص دهد.

05-تخصیص-و-عدم-تخصیص-کاربران-به-کار
تخصیص و عدم تخصیص کاربران به کار

برای بهبود رابط کاربری، اجازه دهید یک مؤلفه ایجاد کنیم که همه کاربران اختصاص داده شده را نشان دهد.

یک جزء 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> ); }

اکنون آزمایش مؤلفه شما نتیجه می دهد:

06-Displaying-specified-users-using-the-AssignedList-component
نمایش کاربران اختصاص داده شده با استفاده از مؤلفه AssignedList

یکی از آخرین اقدامات استفاده از نماد 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> ); }

این می دهد:

07-Removing-users-of-assignment-using-the-AssignedList-component-1
حذف کاربران از انتساب با استفاده از مؤلفه AssignedList

نکته نهایی دیگر بستن فهرست کشویی در برخی از تعاملات کاربر است.

برای شروع، من دوست دارم از یک قلاب قابل استفاده مجدد برای این کار استفاده کنم، که یک عنصر مرجع و یک تابع را می گیرد تا زمانی که هر ناحیه خارج از عنصر هدف من کلیک می شود، شلیک می کند.

 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); });

آزمایش کامپوننت شما اکنون به شما می دهد:

08-بستن-کامپوننت-کشویی-با-کلیک-های خارجی
بستن مؤلفه کشویی با کلیک های خارجی

یا با استفاده از یک دکمه از پیش تعریف شده در بازشو.

 <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> 
09-بستن-بازشو-با-دکمه-تعیین شده
بستن منوی کشویی با دکمه تعیین شده

تغییر نهایی یک تغییر نظری است زیرا اگر در حال حاضر هیچ کاربری به این کار اختصاص داده نشده باشد ترجیح می‌دهم چیز دیگری را نشان دهم.

 {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 را به این موارد می رساند:

10-نمایش-یک-متن-پیش‌فرض-وقتی-هیچ کاربر-تخصیص داده نمی‌شود
نمایش یک متن پیش فرض زمانی که هیچ کاربری اختصاص داده نشده است

روش الگوی اجزای مرکب

حالا برای رویداد اصلی. با ایجاد زمینه ای که کل مؤلفه را در بر می گیرد، شروع کنید.

 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> ); };

و با آن، کامپوننت شما یکسان کار می کند!

11-تکثیر-کارکرد-همان-با-الگوی-کامپوننت-ترکیب
تکرار همان عملکرد با الگوی جزء مرکب

اما چرا اینجا توقف کنید؟

با این الگو، تغییر ظاهر کامپوننت به آسانی تغییر ترتیبی است که آنها را در والد آنها رندر می کنید. به عنوان مثال، اگر ابتدا دکمه را می خواستید، به سادگی ترتیب در بسته بندی اصلی را تغییر دهید.

 <UserAssignDropdown assignedList={assignedList} setAssignedList={setAssignedList} users={usersArray} > <UserAssignDropdown.Button /> <UserAssignDropdown.Header /> <UserAssignDropdown.AssignedList /> </UserAssignDropdown>

و UI بر این اساس پاسخ می دهد.

04-ترتیب-رندر-در-کامپوننت-تغییر شد
ترتیب رندر در جزء مرکب تغییر کرد

این مولفه همچنین به اندازه کافی انعطاف پذیر است تا طرح بندی عناصر را از طریق 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> ) ); };

شما به راحتی می توانید ظاهر کامپوننت را تغییر دهید.

12-استفاده از-props-to-customize-the-compound-component
استفاده از لوازم جانبی برای سفارشی کردن مولفه مرکب

مقایسه بین روش Regular و Compound Component

خوب، بیایید یک قدم به عقب برگردیم و دو رویکردی را که اخیراً تحلیل کردیم، مقایسه کنیم.

سادگی و سازماندهی

روش معمولی : آن را مانند پختن یک کیک در یک کاسه بزرگ تصور کنید. با روش معمولی، می‌توانیم یک مؤلفه واحد ایجاد کنیم که مسئول همه چیز در منوی کشویی است - دکمه، فهرست و همه مواد تشکیل دهنده. مثل این است که یک کارت دستور پخت بزرگ داشته باشید که تمام مراحل آن به هم ریخته باشد. این کار کار را انجام می دهد، اما ممکن است کمی کثیف و سخت باشد، به خصوص زمانی که می خواهید فقط یک قسمت از دستور غذا را تغییر دهید.

روش اجزای مرکب : حالا تصور کنید برای هر ماده کاسه های مختلفی داریم، یک کاسه جداگانه برای آرد، دیگری برای شکر و غیره. این الگوی اجزای مرکب است. هر قسمت از کرکره فضای خاص خود را برای درخشش دارد. این مانند سازماندهی آشپزخانه شماست – هر چیزی جای خود را دارد. این امر درک و اصلاح آن را آسان تر می کند. آیا نیاز به تغییر آرد دارید؟ شما فقط می دانید به کجا نگاه کنید.

انعطاف پذیری و سفارشی سازی

روش معمولی : با رویکرد تک کاسه‌ای ما، ایجاد تغییرات در بخش‌های خاصی از فهرست کشویی می‌تواند کمی شبیه تلاش برای تعویض مواد در آن مخلوط کیک بزرگ باشد. مطمئنا، شما می توانید آن را انجام دهید، اما همیشه آسان نیست. طعم متفاوت کیک می خواهید؟ ممکن است لازم باشد کل کاسه را حفر کنید تا کجا آن را اضافه کنید.

روش اجزای مرکب : با الگوی اجزای ترکیبی، مانند این است که برای هر طعم ظروف جداگانه ای داشته باشید. آیا نیاز به اضافه کردن چیپس شکلات دارید؟ فقط ظرف شکلات را بردارید و بپاشید. هر جزء کار خود را دارد و سفارشی کردن آن را ساده‌تر می‌کند. آیا می خواهید رنگ دکمه را تغییر دهید؟ مشکلی نیست، همان جا در ظرفش است.

استفاده مجدد و نگهداری

روش معمولی : وقتی دستور پخت شما در یک کاسه مخلوط می شود، استفاده مجدد از قسمت هایی از آن برای یک غذای دیگر دشوار است. به‌علاوه، با شلوغ‌تر شدن آشپزخانه‌تان، آشفتگی همه‌چیز آسان‌تر و پیگیری آن‌ها سخت می‌شود. ممکن است هر بار که می خواهید چیز جدیدی درست کنید، دستور غذا را بازنویسی می کنید.

روش اجزای مرکب : با الگوی اجزای مرکب، مانند این است که مجموعه ای از ابزارهای قابل استفاده مجدد در آشپزخانه خود داشته باشید. آیا نیاز به تهیه یک کیک متفاوت دارید؟ فقط ابزار مورد نیاز خود را بردارید و پخت را انجام دهید. هر جزء مانند یک ابزار تخصصی است – استفاده مجدد و نگهداری آن آسان است. و هنگامی که آشپزخانه شما سازماندهی شده است، نسیمی است که چیز جدیدی را تولید کنید.

اطلاعات تکمیلی

در اینجا پیوندهایی به تمام منابعی که ممکن است از این مقاله نیاز داشته باشید وجود دارد.

فایل های شروع کننده

الگوی عملکرد منظم

الگوی کامپوننت مرکب

نتیجه

در پایان، هر دو روش جای خود را در آشپزخانه دارند - منظورم این است که در کد شما. روش معمولی مانند کاسه همزن قدیمی شما است - قابل اعتماد و آشنا، اما شاید برای هر دستور غذا کارآمدترین روش نباشد.

اجزای ترکیبی Pattern مانند یک آشپزخانه منظم است که همه چیز در جای خود و آماده کار است. ممکن است راه اندازی کمی بیشتر طول بکشد، اما می تواند زندگی شما را در دراز مدت بسیار آسان تر کند. پس ، بسته به آنچه که در حال پختن هستید، روشی را انتخاب کنید که مطابق با سلیقه شما باشد – و کدنویسی شاد! 🍰🎨

اطلاعات تماس

می خواهید به من وصل شوید یا با من تماس بگیرید؟ در صورت تمایل به من در مورد موارد زیر ضربه بزنید:

توییتر / X: @jajadavid8

لینکدین: دیوید جاجا

ایمیل: Jajadavidjid@gmail.com

خبرکاو

ارسال نظر




تبليغات ايهنا تبليغات ايهنا

تمامی حقوق مادی و معنوی این سایت متعلق به خبرکاو است و استفاده از مطالب با ذکر منبع بلامانع است