کوئری مدیا در React به روش برنامه نویسی شده – راهنمای کاربردی


طراحی «نقاط توقف» (breakpoints) مبتنی بر کوئری مدیا در فریمورک React.js برخی اوقات برای دستکاری UI به صورت درجا به جای نوشتن CSS و سپس نوشتن کوئری مدیا برای آن بسیار کارآمد خواهد بود. در این مقاله به بررسی پیادهسازی قلاب useBreakpoint با استفاده از روشهایی به جز رویداد resize میپردازیم. بدین ترتیب با کاربرد کوئری مدیا در React به روش برنامهنویسیشده آشنا میشویم.
مطابقت دادن مدیا
برای دستیابی به نقاط توقف کوئری مدیا باید شروع به بررسی مدیای خود بکنیم. به عبارت دیگر باید دستگاههایی که اپلیکیشن روی آنها اجرا شده بررسی کنیم و ببینیم اندازه صفحه کوچک یا بزرگ دارند. به این منظور جاوا اسکریپت یک متد به نام matchMedia روی شیء window ارائه میکند.
به طور مشابه بررسی میکنیم که چه زمانی سند بیشینه عرض 100 پیکسل دارد. متد matchMedia یک شیء MediaQueryList بازگشت میدهد که نماینده نتایج تحلیل شده کوئری مدیای مورد نظر است.
اساساً این شیء MediaQueryList همان چیزی است که برای تعیین زمان تطبیق document با کوئری مدیا مورد استفاده قرار میدهیم و همچنین document را رصد میکنیم تا تشخیص دهیم چه هنگام با کوئری مدیا مطابقت دارد یا ندارد.
استفاده از MediaQueryList
در زمان استفاده از MediaQueryList دو حالت پیش میآید:
- هنگامی که میخواهیم بیدرنگ بررسی کنیم آیا سند ما با کوئری مدیا مطابقت دارد یا نه و یا وقتی میخواهیم این موضوع را تنها یک بار و احتمالاً پس از نصب شدن کامپوننت اصلی ریاکت بررسی کنیم.
- هنگامی که به صورت مرتب بررسی میکنیم آیا سند با کوئری مدیا مطابقت دارد یا نه. این حالت زمانی رخ میدهد که دستگاهی داشته باشیم که عرض یا طول صفحه آن بتواند تغییر یابد. مثلاً هنگامی که جهت گوشی از عمودی به افقی عوض میشود، چنین حالتی پیش میآید.
در این حالت، هنگامی که لازم باشد بررسی آنی انجام دهیم، میتوانیم از مشخصههای matches در MediaQueryList استفاده کنیم. این یک مشخصه بولی است که اگر سند در حال حاضر با لیست کوئری مدیا مطابقت داشته باشد مقدار true و در غیر این صورت مقدار false بازگشت میدهد:
در مورد حالت دوم، باید رویداد change را روی شیء MediaQueryList رصد کنیم. این شیء برای آغاز گوش دادن به رویداد change، یک متد به نام ()addListener ارائه کرده است. به طور مشابه برای توقف گوش دادن باید از متد ()removeListener استفاده کنیم.
تابع گوش دادن هر بار که عرض سند تغییر یافت و یا جهتگیری دستگاه عوض شد، فراخوانی نمیشود، بلکه تنها در دو حالت احضار میشود. یکی زمانی که سند با mediaQueryString مطابقت پیدا کند و دوم زمانی که مطابقت آن با mediaQueryString از دست برود.
چه کار باید بکنیم؟
ما یک شیء از کاربر قلاب سفارشی خود انتظار داریم. در این شیء مقدار هر مشخصه یک رشته کوئری مدیا دارد:
در خروجی نیز انتظار دریافت یک شیء داریم که همه کلیدهای ارائه شده در شیء queries را داشته باشد. در این شیء هر مقدار مشخصه/کلید بولی خواهد بود. در صورتی که گزاره مطابقت یابد، مقدار آن true و در غیر این صورت مقدار آن false خواهد بود.
برای نمونه فرض کنید عرض صفحه ما 640 پیکسل است. در این صورت خروجی که برای queries فوق انتظار داریم به صورت زیر خواهد بود:
برای به دست آوردن خروجی فوق مراحل زیر را طی میکنیم:
- حلقهای تعریف میکنیم که روی هر مشخصه شیء queries چرخیده و برای هر کوئری ()matchMedia را فرا میخواند (کد در ادامه ارائه شده است).
- هر فراخوانی به matchMedia برای یک کوئری یک شیء MediaQueryList برای آن کوئری بازگشت میدهد. ما شیء MediaQueryList را در یک شیء جدید ذخیره میکنیم که متناظر با همان کلید است.
- ضمناً برای به دست آوردن کوئری مطابق با سند (document) جاری و دانستن نوع دستگاه در زمان آغاز به کار، از مشخصه matches روی همه شیءهای MediaQueryList استفاده میکنیم.
اکنون باید حالتهایی که کوئریهای ما در شیء queries تغییر مییابند را نیز مدیریت کنیم. اینها مواردی هستند که سند مطابقت با یک کوئری را آغاز کرده یا خاتمه میبخشد. به این منظور با استفاده از ()addListener به رویداد change روی هر یک از آیتمهای MediaQueryList گوش میکنیم (به کد زیر توجه کنید).
یک تابع handler تعریف میکنیم که در آن روی همه کلیدهای شیء queries میچرخیم و نتیجه مشخصه matches را برای هر شیء MediaQueryList ذخیره مینماییم.
نکته: این تابع handler هر زمان که سند شروع به مطابقت با یک کوئری در شیء queries بکند یا این مطابقت متوقف شود فراخوانی خواهد شد.
پیادهسازی در ریاکت
بررسی کوئری مدیا در کد ما به صورت یک اثر جانبی است و از این رو این منطق را درون قلاب useEffect قرار میدهیم. همچنین باید بررسی کنیم آیا مرورگر از matchMedia پشتیبانی میکند یا نه.
در همین راستا یک «حالت» (State) نگهداری میکنیم که نتیجه همه کوئریهای مدیا را که با document مطابقت دارد یا ندارد ذخیره میکند.
اکنون از این قلاب مانند هر قلاب دیگری در اپلیکیشن خود استفاده میکنیم.
آیا این روش کارآمدی محسوب میشود؟
شاید متوجه شده باشید که این روش چندان بهینه نیست، زیرا اگر مجبور باشیم از قلاب useBreakpoint در هزاران کامپوننت استفاده کنیم، باید useBreakpoint را بارها و بارها فراخوانی کنیم.
بدین ترتیب در صورتی که از چند کامپوننت نصب شده استفاده کنیم و همه آنها از قلاب useBreakpoint استفاده کنند، باید شنونده رویداد change را ثبت کنیم که بسیار غیر بهینه است.
روش بهینه کدام است؟
برای حل این مشکل باید از context ریاکت استفاده کنیم. بنابراین به جای استفاده مستقیم از React context از context بهره میگیریم و سپس آن را در قلاب سفارشی خود مورد استفاده قرار میدهیم. با استفاده از React.createContext(defaltValue) اقدام به ساخت context میکنیم.
ما باید کدی را که میخواهیم به مقدار context دسترسی داشته باشد، درون یک Provider قرار دهیم. در این مورد از BreakpointContext.Provider استفاده میکنیم. سپس برای دسترسی به این مقدار از قلاب ریاکت به نام useContext استفاده میکنیم.
اما به جای استفاده مستقیم از BreakpointContext.Provider یک پوشش پیرامون آن ایجاد میکنیم:
useBreakpoint یک تابع است که در آن مقدار context را بازگشت میدهیم و اساساً با نتیجه کوئری مطابقت داد.
ما اپلیکیشن خود را در BreakpointProvider قرار میدهیم و یک prop کوئری به آن ارسال میکنیم. به این ترتیب useBreakpoint تنها میتواند در کامپوننتهای قرار گرفته درون BreakpointProvider مورد استفاده قرار گیرد. بدین ترتیب در نهایت همه چیز را در کنار هم قرار میدهیم:
کاربرد
روش بکارگیری BreakpointProvider به صورت زیر است:
روش بکارگیری با useBreakpoint به صورت زیر است:
با استفاده از این روش میتوانیم علاوه بر بررسی max-width یا min-width، جهتگیری افقی یا عمودی دستگاه و بسیاری از کوئریهای مدیای دیگر را نیز اجرا کنیم.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای JavaScript (جاوا اسکریپت)
- مجموعه آموزشهای برنامهنویسی
- آموزش ساخت پروژه با فریم ورک React Native
- ری اکت (React) — راهنمای جامع برای شروع به کار
- آموزش ری اکت (React) — مجموعه مقالات مجله فرادرس
==