رندر کادرهای Modal در React — به زبان ساده

۲۳۹ بازدید
آخرین به‌روزرسانی: ۲۰ شهریور ۱۴۰۲
زمان مطالعه: ۳ دقیقه
رندر کادرهای Modal در React — به زبان ساده

کادرهای Modal می‌توانند موضوعات پیچیده‌ای باشند، زیرا روش ری‌اکت برای سازماندهی DOM چنین است. اگر با مبانی ری‌اکت آشنا باشید، می‌دانید که کل اپلیکیشن یک کامپوننت است که معمولاً </ App> نامیده می‌شود و به عنوان یک فرزند به یک <div> به نام root# الحاق می‌شود. فایل index.html چیزی مانند زیر است:

ری‌اکت
فایل public/index.html برای ایجاد ری‌اکت

زمانی که کامپوننت </ App> در DOM رندر شد، عنصر واقعی <div> در HTML با id #root کل اپلیکیشن React را درون خود رندر می‌کند.

در نتیجه، این وضعیت که کامپوننت‌های اپلیکیشن React کاملاً تو در تو باشند، امری رایج محسوب می‌شود. منظور ما از تو در تو، ده‌ها سطح و یا بیشتر است. بنابراین اگر یکی از این سطوح کاملاً عمیق در لایه‌های تو در تو بخواهد یک modal را نمایش دهد، با برخی مشکلات جدی CSS مواجه می‌شود.

Modal-ها یک لایه روی صفحه قرار می‌دهند و از این رو اولویت نمایشی بالاتری نسبت به همه عناصر دیگر دارند. اگر بخواهید آن را برحسب z-index تعیین کنید، باز هم کاملاً تو در تو خواهد بود و عناصر والد در سطوح بالاتر CSS تقدم خواهند داشت.

بنابراین به جای این که با CSS سر و کله بزنیم که به تنظیم دقیق نیاز دارد و هر آن ممکن است اپلیکیشن را به هم بریزد، باید روشی برای رندر کردن DOM در خارج از این ساختار کاملاً تو در تو پیدا کنیم.

راه‌حل: پورتال‌های React

یک راهبرد استفاده از پورتال‌های ReactDOM است و بدین ترتیب Modal را در یک div قرار می‌دهیم که کامپوننت هم‌نیای div با id به صورت #root است. بدین ترتیب سبک‌های CSS اعمال شده روی div wrapper برای Modal تنها در رابطه با هم‌نیای آن که root# است، اعمال می‌شوند و از این رو سبک‌بندی CSS برای root# به هم نمی‌ریزد.

برای انجام این کار باید از متد ()createPortal در ReactDOM استفاده کنیم. یک پورتال عملاً یک div هم‌نیا است و این قاعده را که همه کامپوننت‌های React باید فرزندان <"div id=”root> باشند را دور می‌زند. به این منظور باید کارهای زیر را انجام دهیم:

کد زیر را در فایل index.html و درون تگ <body> قرار دهید:

1<body>
2    <noscript>
3      You need to enable JavaScript to run this app.
4    </noscript>
5    
6    <div id="root"></div>
7    
8    <div id="modal"></div> .   //ADD THIS
9    
10  </body>
11</html>

یک کامپوننت Modal.js ایجاد کنید (classNames از semantic-UI گرفته شده):

1import React from "react";
2import ReactDOM from "react-dom";
3
4const JSX_MODAL = (
5  <div className="ui dimmer modals visible active">  
6    <div className="ui standard modal visible active">
7      THIS IS SOME TEXT IN THE MODAL // add some UI features here
8    </div>
9  </div>
10);
11
12
13function Modal(props) {
14  return ReactDOM.createPortal(JSX_MODAL, document.querySelector("#modal"));
15}
16
17
18export default Modal;

می‌بینید که createPortal دو آرگومان می‌گیرد که در یکی برخی اسکریپت‌های JSX که رندر می‌شوند و مشابه ReactDOM.render هستند و دیگری عنصر هدف است که باید JSX را رندر کند.

اگر کامپوننت را رندر و به آن مراجعه کنید، مشاهده خواهید کرد که همه چیز به درستی نمایش می‌یابد. اینک باید handler مناسب را به ()onClick اضافه کنید تا زمانی که کاربر درون رابط کاربری modal کلیک کرد عمل مناسب را انجام دهد و در صورتی که خارج از آن کلیک کرد نیز آن را پنهان سازد.

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

قابلیت استفاده مجدد (Reusability)

مثال فوق کاملاً ابتدایی است و قصد ما نیز این نبوده که یک قطعه کد آماده استفاده ارائه کنیم. بلکه، کدی که ما نوشته‌ایم یک راه‌حل است که برای رفع مشکل modal-ها ارائه شده است. شما باید این کامپوننت را بر اساس نیازهای خودتان سفارشی‌سازی کنید. از مفاهیم React برای قابلیت استفاده مجدد استفاده کنید تا مطمئن شوید که داده‌های کدنویسی شده سخت (یعنی داده‌هایی که قابلیت استفاده مجدد نمی‌یابند) در Modal ندارید و محتوا و حتی ویجت‌های کوچک را نیز بنا به نیاز ارسال می‌کنید.

برای نمونه می‌توانید یک modal داشته باشید که وقتی کاربر قصد دارد چیزی را از پایگاه داده حذف کند، نمایش دهید. این کامپوننت می‌تواند نامی مانند </DeleteThis> داشته باشد. این کامپوننت یک </ Modal> است یعنی که یک لایه رویی است که صفحه </ DeleteThis> زیرین را تیره می‌کند.

درون </ Modal> یک کامپوننت داخلی به نام </ InnerModal> قرار دارد و این کامپوننت همان کامپوننت تعاملی اصلی را در خود جای داده است که هدر، محتوا و متن دارد.

بنابراین کامپوننت </ DeleteThis> اقدام به ایجاد props می‌کند که به <Modal /> ارسال می‌شود و به نوبه خود در </ InnerModal> قرار می‌گیرد. از این رو متد رندر </ DeleteThis> به صورت زیر خواهد بود:

1render() {
2    return (
3      <div>
4        <Modal
5          content={this.renderContentProp()}   
6          header="Delete this?"                
7          actions={this.renderActionButtons()}
8          onDismiss={this.onDismiss}
9        />
10      </div>
11    );
12  }
13  
14  renderActionButtons = () => {
15    //return JSX that renders action buttons...
16    return (
17      <div>
18        <div className="ui button primary">Delete</div>
19        <div className="ui button">Cancel</div>
20      </div>
21    );
22};

کامپوننت واقعی  Modal به صورت زیر است:

1import React from "react";
2import ReactDOM from "react-dom";
3import ModalInner from './modal-inner'
4
5function Modal(props) {
6  return ReactDOM
7    .createPortal(
8       <ModalInner {...props} />,
9       document.querySelector("#modal")                      //target DOM element
10     );
11}
12export default Modal;

و اینک در نهایت می‌توانیم آن را رندر کنیم:

Modal

بدین ترتیب موفق شدیم این کار را به انجام برسانیم و اینک Modal-ها با پورتال React کار می‌کنند.

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۲ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
freecodecamp
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *