سلام دوستان 👋 توی این قسمت میخوایم ببینیم که Portal توی ریاکت چه کاربردهایی داره و چه زمانی پیشنهاد میشه از اون استفاده کنیم. این پست از مجموعه پستهای ریاکت ۱۰۱ هست. بریم که پست امروز رو شروع کنیم.
React Portal؟ 🤔
Portal (که از این بعد بهش میگیم پرتال) یک ویژگی توی ریاکت هست که اجازه میده یک المنت رو توی جای دلخواه از DOM رندر کنیم. در حالت عادی یک المنت همون جایی رندر میشه که صدا زده شده. اما گاهی اوقات میخوایم اون المنت رو جای دیگهای از صفحه رندر کنیم. برای این کار این ویژگی به کارمون میاد.
پرتال کاربردهای خاص و مهمی داره و معمولاً توسط کامپوننتهای مُدال (Modal) و Tooltip و Popover استفاده میشه. فرض کنیم یک کامپوننت مُدال نوشتیم و اون رو میخوایم توی یک کامپوننت دیگه فراخونی کنیم. اگه کامپوننت والد یکسری استایلهای خاص مثل overflow: hidden داشته باشه و یا طول و عرض اون محدود باشه، کامپوننت مُدال بهدرستی نمایش داده نمیشه. اینجاست که باید کاری کنیم که مُدال به جای دیگهای از DOM منتقل بشه تا بهراحتی نمایش داده بشه.
چه جوری از قابلیت پرتال استفاده کنیم؟
با استفاده از کد زیر میتونیم از قابلیت پرتال توی ریاکت استفاده کنیم:
import { createPortal } from "react-dom"; createPortal(child, container);
همونطور که میبینیم متد createPortal رو داریم از react-dom فراخونی میکنیم. این تابع ۲ ورودی میگیره. ورودی اول کامپوننتی هست که میخوایم رندر کنیم (مثلا مُدال.) در واقع این ورودی هر چیز قابل رندر شدنی رو قبول میکنه. مثل المنتهای JSX و رشته و اعداد. ورودی دوم المنتی هست که میخوایم کامپوننت مد نظر ما توش رندر داده بشه. این المنت باید توی DOM وجود داشته باشه.
اگه بخوایم یه مثال ساده بزنیم:
export default function App() { const Welcome = <h1>Welcome!</h1> const container = document.body; return createPortal(Welcome, container); }
به return خط ۵ دقت کنین. خروجی متد createPortal یک المنت ریاکتی یا JSX هست. پس برای اینکه توی صفحه رندر بشه باید توسط کامپوننت ریترن بشه. توی کد بالا، createPortal کامپوننت Welcome رو در انتهای المنت <body> رندر میکنه.
با توجه به کد بالا، نکتهٔ مهمی که باید در نظر داشته باشیم اینه که کامپوننتهای مد نظر ما حتماً لازم نیست توی قسمتی رندر بشن که ریاکت داره اونجا رو مدیریت میکنه. پس اونها رو میتونیم هر جای دلخواهی از DOM رندر کنیم.
پس Event Propagation چی میشه؟
المنتی که توسط createPortal رندر شده، در واقع فقط موقعیت فیزیکی اون توی DOM تغییر میکنه. برای مثال یک کامپوننت میسازیم که میخوایم اون رو جای دیگه از صفحه رندر کنیم:
export default function Welcome() { const [counter, setCounter] = useState(0); return ( <button onClick={() => setCounter(counter + 1)}> Welcome 🖐️ × {counter} </button> ); }
و به این صورت از اون استفاده میکنیم:
import Welcome from "./Welcome"; export default function App() { return ( <div onClick={() => alert("You clicked on me!")}> <<createPortal(<Welcome />, document.body)>> </div> ); }
با اجرا شدن کد بالا، اگه روی button که توی کامپوننت Welcome هست کلیک کنیم، alert توی کامپوننت App هم اجرا میشه. در صورتی که ما گفته بودیم کامپوننت Welcome انتهای <body> رندر بشه. خروجی کد برنامهٔ بالا (روی دکمه کلیک کنید):
پس نتیجه میگیریم که کامپوننت وابستگیش رو به جایی که فراخونی شده حفظ میکنه. از روی همین قانون میشه نتیجه گرفت که کامپوننت میتونه به اجزای کامپوننت والد دسترسی داشته باشه. مثلاً اگه یک کانتکست (Context) داریم توی کامپوننت والد، کامپوننت پورتال شده باز هم میتونه به این کانتکست دسترسی داشته باشه.
پورتالها و SSR
از createPortal فقط میتونیم توی کلاینت-ساید استفاده کنیم. پس این قابلیت روی توی SSR نداریم و نباید اون رو توی شرایطی که کدهای ما سمت سرور اجرا میشه صدا بزنیم.
خب دوستان این بود چیزایی که باید از پرتالها میدونستیم. امیدوارم از اطلاعاتی که توی این قسمت بررسی کردیم استفاده کرده باشین. تا یک قسمت دیگه روزتون خوش 😉👋
