اشتراکها
اشتراکها
تعریف Business Intelligence
اشتراکها
پروژه River Trail
اشتراکها
استفاده مناسب از Lazy Loading در ef
در راهنمای کدنویسی Angular توصیه شده از اینترفیسها برای تعریف نوع مدلها استفاده شود:
در کل سلیقهای است و بهتر است یکنواختی و یکدستی کد مدنظر باشد.
Consider using a class instead of an interface for services and declarables (components, directives, and pipes)
Consider using an interface for data models
البته این مورد موافقها و مخالفهایی هم دارد.در کل سلیقهای است و بهتر است یکنواختی و یکدستی کد مدنظر باشد.
Buffer Pool یکی از مصرف کنندگان اصلی حافظه در SQL Server است. برای مثال زمانیکه اطلاعاتی را از بانک اطلاعاتی دریافت میکنید، این دادهها در Buffer Pool کش میشوند. همچنین SQL Server اطلاعات کلیه Execution Plans را نیز در Plan Cache که جزئی از Buffer Pool است، برای استفادهی مجدد نگهداری میکند. هر چقدر حافظهی فیزیکی سرور شما بیشتر باشد، مقدار Buffer Pool نیز به همین میزان افزایش خواهد یافت که البته حداکثر آنرا میتوان در تنظیمات حافظهی سرور محدود کرد (Max Server Memory setting).
در دنیای واقعی میزان حافظهی فیزیکی سرورها محدود است. در SQL Server 2014 راه حلی برای این مشکل تحت عنوان Buffer Pool Extensions ارائه شدهاست که محل قرارگیری آنرا در تصویر ذیل مشاهده میکنید:
Buffer Pool Extensions از یک فایل ساده که به آن Extension File نیز گفته میشود، تشکیل شدهاست و امکان ذخیره سازی آن بر روی هاردهای سریعی مانند SSD Driveها میسر است. این فایل، ساختاری را همانند page file، در سیستم عامل ویندوز دارد. در این حالت بجای اضافه کردن RAM بیشتر به سرور، یک Extension File را میتوان بکار گرفت. هر زمان که Buffer Pool اصلی تحت فشار قرار گیرد (به میزان حافظهای بیش از حافظهی فیزیکی سرور نیاز باشد)، از این افزونهی فایلی استفاده خواهد شد.
اطلاعات جزئیات Buffer Pool را توسط کوئری ذیل میتوان بدست آورد:
نحوهی فعال سازی و تنظیم Buffer Pool Extensions
قبل از هر کاری بهتر است وضعیت افزونهی Buffer pool را بررسی کرد:
همانطور که ملاحظه میکنید، در حالت پیش فرض غیرفعال است.
سپس یک فایل یک گیگابایتی را به عنوان افزونهی Buffer pool ایجاد میکنیم.
توصیه شدهاست که این فایل را در یک درایور پر سرعت SSD قرار دهید؛ ولی محدودیتی از لحاظ محل قرارگیری ندارد (هر چند به نظر فقط در حالتیکه از SSD Drive استفاده شود واقعا کار میکند).
اینبار اگر کوئری اول را اجرا کنیم، چنین خروجی قابل مشاهده است:
این فایل به صورت خودکار در حین ریاستارت یا خاموش شدن سرور، حذف شده و با راه اندازی مجدد آن، باز تولید خواهد شد.
تغییر اندازهی افزونهی Buffer pool
اگر سعی کنیم، یک گیگابایت را مثلا به 10 گیگابایت افزایش دهیم:
با خطای ذیل مواجه خواهیم شد:
برای رفع این مشکل، ابتدا باید افزونهی Buffer pool را غیرفعال کرد:
سپس میتوان مجددا اندازه و یا مسیر دیگری را مشخص کرد. بهتر است اندازهی این فایل را حدود 16 برابر حداکثر میزان حافظهی سرور (Max Server Memory) تعیین کنید.
همچنین توصیه شدهاست که پس از غیرفعال کردن این افزونه، بهتر است یکبار instance جاری را ری استارت کنید.
چه زمانی بهتر است از افزونهی Buffer pool استفاده شود؟
در محیطهای read-heavy OLTP، استفاده از یک چنین افزونهای میتواند میزان کارآیی و پاسخگویی سیستم را به شدت افزایش دهد (تا 50 درصد).
سؤال: آیا غیرفعال کردن افزونهی Buffer pool سبب از دست رفتن اطلاعات میشود؟
خیر. BPE، تنها clean pages را در خود ذخیره میکند؛ یعنی تنها اطلاعاتی که Commit شدهاند در آن حضور خواهند داشت و در این حالت حذف آن یا ری استارت کردن سرور، سبب از دست رفتن اطلاعات نخواهند شد.
برای مطالعه بیشتر
Buffer Pool Extension
SQL Server 2014 Buffer Pool Extensions
Do you require a SSD to use the Buffer Pool Extension feature in SQL Server 2014
Buffer Pool Extensions in SQL Server 2014
SQL Server 2014 – Buffer Pool Extension
در دنیای واقعی میزان حافظهی فیزیکی سرورها محدود است. در SQL Server 2014 راه حلی برای این مشکل تحت عنوان Buffer Pool Extensions ارائه شدهاست که محل قرارگیری آنرا در تصویر ذیل مشاهده میکنید:
Buffer Pool Extensions از یک فایل ساده که به آن Extension File نیز گفته میشود، تشکیل شدهاست و امکان ذخیره سازی آن بر روی هاردهای سریعی مانند SSD Driveها میسر است. این فایل، ساختاری را همانند page file، در سیستم عامل ویندوز دارد. در این حالت بجای اضافه کردن RAM بیشتر به سرور، یک Extension File را میتوان بکار گرفت. هر زمان که Buffer Pool اصلی تحت فشار قرار گیرد (به میزان حافظهای بیش از حافظهی فیزیکی سرور نیاز باشد)، از این افزونهی فایلی استفاده خواهد شد.
اطلاعات جزئیات Buffer Pool را توسط کوئری ذیل میتوان بدست آورد:
Select * from sys.dm_os_buffer_descriptors
نحوهی فعال سازی و تنظیم Buffer Pool Extensions
قبل از هر کاری بهتر است وضعیت افزونهی Buffer pool را بررسی کرد:
select * from sys.dm_os_buffer_pool_extension_configuration
همانطور که ملاحظه میکنید، در حالت پیش فرض غیرفعال است.
سپس یک فایل یک گیگابایتی را به عنوان افزونهی Buffer pool ایجاد میکنیم.
ALTER SERVER CONFIGURATION SET BUFFER POOL EXTENSION ON (FILENAME = 'd:\BufferPoolExt.BPE', SIZE = 1GB);
اینبار اگر کوئری اول را اجرا کنیم، چنین خروجی قابل مشاهده است:
این فایل به صورت خودکار در حین ریاستارت یا خاموش شدن سرور، حذف شده و با راه اندازی مجدد آن، باز تولید خواهد شد.
تغییر اندازهی افزونهی Buffer pool
اگر سعی کنیم، یک گیگابایت را مثلا به 10 گیگابایت افزایش دهیم:
ALTER SERVER CONFIGURATION SET BUFFER POOL EXTENSION ON (FILENAME = 'd:\BufferPoolExt.BPE', SIZE = 10GB);
Could not change the value of the 'BPoolExtensionPath' property
ALTER SERVER CONFIGURATION SET BUFFER POOL EXTENSION OFF
همچنین توصیه شدهاست که پس از غیرفعال کردن این افزونه، بهتر است یکبار instance جاری را ری استارت کنید.
چه زمانی بهتر است از افزونهی Buffer pool استفاده شود؟
در محیطهای read-heavy OLTP، استفاده از یک چنین افزونهای میتواند میزان کارآیی و پاسخگویی سیستم را به شدت افزایش دهد (تا 50 درصد).
سؤال: آیا غیرفعال کردن افزونهی Buffer pool سبب از دست رفتن اطلاعات میشود؟
خیر. BPE، تنها clean pages را در خود ذخیره میکند؛ یعنی تنها اطلاعاتی که Commit شدهاند در آن حضور خواهند داشت و در این حالت حذف آن یا ری استارت کردن سرور، سبب از دست رفتن اطلاعات نخواهند شد.
برای مطالعه بیشتر
Buffer Pool Extension
SQL Server 2014 Buffer Pool Extensions
Do you require a SSD to use the Buffer Pool Extension feature in SQL Server 2014
Buffer Pool Extensions in SQL Server 2014
SQL Server 2014 – Buffer Pool Extension
اشتراکها
کتاب Cryptography in .NET Succinctly
Irresponsible ownership of data is the cause of many leaked emails,
data, and other damaging information. Securing a user’s personal
information is the job of software developers. If you, as a developer,
can decrypt the information stored in the database of the system you are
working on, then so can anyone else. In Cryptography in .NET Succinctly,
Dirk Strauss will take readers through generating cryptographic
signatures, hashing and salting passwords, and when and how to use
symmetric vs. asymmetric encryption.
React برخلاف Angular، دارای قابلیتهای توکار مسیریابی نیست و تنها کاری را که انجام میدهد همان رندر View است که تا اینجا بررسی کردیم. به همین جهت در این قسمت ابتدا یک برنامهی عمومی و ساده را با نصب کتابخانهی ثالثی برای توضیح مفاهیم مسیریابی، شامل کار با پارامترهای مسیریابی، کوئری استرینگها، هدایت کاربران به صفحات دیگر، مدیریت صفحات یافت نشده و مسیریابی تو در تو، بررسی میکنیم. سپس به عنوان تمرین، همان برنامهی طراحی گریدی را که تا قسمت 14 تکمیل کردیم، با معرفی مسیریابی بهبود خواهیم بخشید.
برپایی پیشنیازها
در اینجا برای بررسی مسیریابی، یک پروژهی جدید React را ایجاد میکنیم.
در ادامه توئیتر بوت استرپ 4 را نیز نصب میکنیم. برای این منظور پس از باز کردن پوشهی اصلی برنامه توسط VSCode، دکمههای ctrl+` را فشرده (ctrl+back-tick) و دستور زیر را در ترمینال ظاهر شده وارد کنید:
سپس برای افزودن فایل bootstrap.css به پروژهی React خود، ابتدای فایل index.js را به نحو زیر ویرایش خواهیم کرد:
این import به صورت خودکار توسط webpack ای که در پشت صحنه کار bundling & minification برنامه را انجام میدهد، مورد استفاده قرار میگیرد.
همچنین کتابخانهی ثالث بسیار معروف react-router-dom را نیز نصب میکنیم:
نگارش dom آن مخصوص کار با مرورگر است و نگارش native آن (react-router-native)، مخصوص React Native و تولید برنامههای موبایل میباشد که مبحث دیگری است.
افزودن مسیریابی به برنامه
پس از نصب کتابخانهی react-router-dom، برای افزودن آن به برنامه و فعالسازی مسیریابی، به فایل index.js مراجعه کرده و import آنرا به ابتدای فایل اضافه میکنیم:
سپس کامپوننت App را داخل BrowserRouter، محصور میکنیم:
کار BrowserRouter، محصور سازی مدیریت تاریخچهی مرور صفحات در مرورگر و انتقال آن به درخت کامپوننتهای React است. به این ترتیب در هر قسمتی از درخت کامپوننتهای برنامه میتوان از History object مرورگر استفاده کرد.
ثبت و معرفی مسیریابیها
در ادامه باید مسیریابیهای خود را ثبت کنیم؛ به این معنا که بر اساس URL خاصی، چه کامپوننتی باید رندر شود. به همین جهت پوشهی جدید src\components را ایجاد کرده و کامپوننت src\components\navbar.jsx را که یک کامپوننت تابعی بدون حالت است، در آن تعریف میکنیم:
کار آن نمایش منوی بالای صفحه است.
سپس به فایل app.js مراجعه کرده و ساختار آنرا به صورت زیر، جهت درج این NavBar، ویرایش میکنیم تا سبب رندر و نمایش منوی راهبری در مرورگر شود:
در ادامه در کامپوننت App، یک container را اضافه میکنیم که قرار است در آن بر اساس URL رسیده، محتوای کامپوننت خاصی رندر شود. به همین جهت کامپوننت Route را در اینجا قرار میدهیم و در آن یک یا چند Route را ثبت میکنیم:
Route نیز یک کامپوننت است؛ همانند تمام کامپوننتهایی که تاکنون تعریف کردیم و دارای چند ویژگی است که به صورت props به آن منتقل میشوند. برای نمونه خاصیت path آن به مسیر products/ در مرورگر اشاره میکند و سبب رندر کامپوننت جدید Products که در بالای این ماژول نیز import شده، میشود. در اینجا سه مسیریابی دیگر را نیز ثبت کردهایم که کامپوننتهای جدید متناظر با آنها به صورت زیر تعریف میشوند:
کامپوننت جدید src\components\products.jsx جهت رندر لیست آرایهی اشیاء product:
کامپوننت بدون حالت تابعی src\components\home.jsx با این محتوا:
کامپوننت بدون حالت تابعی src\components\posts.jsx با این محتوا:
کامپوننت بدون حالت تابعی src\components\admin\dashboard.jsx در پوشهی جدید admin با این محتوا:
تا اینجا اگر برنامه را اجرا کنیم، در اولین بار نمایش آن، شاهد رندر کامپوننت Home خواهیم بود. اما اگر در همین حالت بر روی لیست products، در منوی بالای صفحه کلیک کنیم، هم کامپوننت products و هم کامپونت home، هر دو با هم رندر شدهاند. یک چنین رفتاری را در سایر صفحات نیز میتوان مشاهده کرد:
معرفی کامپوننت Switch
الگوریتم تطابق کامپوننت Route، ابتدا بررسی میکند که آیا برای مثال URL ای با path مساوی products/ شروع شدهاست؟ اگر اینطور است، کامپوننت متناظر با آن را که برای نمونه در اینجا Products است، رندر میکند. این حالت جهت مسیری مانند products/new/ نیز صدق میکند؛ چون این URL نیز با products/ شروع شدهاست. همچنین این تطابقگر، مسیر ثبت شدهی برای کامپوننت Home را نیز چون با / شروع شدهاست و جزء ابتدایی مسیر products/ است هم رندر میکند. به همین جهت است که وقتی مسیر products/ را درخواست میدهیم، در صفحه دو کامپوننت products و home، با هم رندر میشوند.
یک روش حل این مشکل، استفاده از ویژگی exact است:
به این ترتیب اگر مسیر درخواستی دقیقا مساوی / بود، کامپوننت Home را رندر خواهد کرد. با این تغییر، با مراجعهی به آدرس products/، دیگر رندر کامپوننت home را شاهد نخواهیم بود:
راه دوم رفع این مشکل، استفاده از کامپوننت Switch است. به همین جهت ابتدا این کامپوننت را import میکنیم:
سپس تمام Routeهای تعریف شده را داخل Switch محصور خواهیم کرد:
Switch اولین مسیریابی را که با URL داده شده تطابق داشته باشد، رندر میکند. همچنین در اینجا دیگر نیازی به ذکر ویژگی exact نیز وجود ندارد. بنابراین با استفاده از Switch اگر مسیر داده شده، products/ باشد، مسیریابی تعریف شدهی با آن یافت میشود که در اینجا اولین Route تعریف شدهاست. سپس کار رندر کامپوننت آنرا انجام داده و از مابقی مسیریابیهای تعریف شده، صرفنظر میکند.
بنابراین هنگام کار با Switch، ترتیب مسیریابیهای تعریف شده مهم است و باید از یک مسیریابی ویژه شروع شده و به یک مسیریابی عمومی مانند / ختم شود.
معرفی کامپوننت Link
تا اینجا اگر برنامه را اجرا کرده باشید و پیشتر سابقهی کار با برنامههای SPA یا Single page applications را داشته باشید، یک مشکل دیگر را نیز احساس کردهاید: سیستم مسیریابی که تا کنون تعریف کردهایم، به صورت SPA عمل نمیکند. یعنی به ازای هربار کلیک بر روی لینکهای منوی راهبری سایت، یکبار دیگر به طور کامل برنامه از صفر بارگذاری مجدد میشود و تمام اسکریپتهای آن مجددا از سرور دریافت شده و رندر خواهند شد. این مورد را در برگهی network ابزارهای توسعه دهندگان مرورگر خود بهتر میتوانید مشاهده کنید. به ازای هر درخواست نمایش کامپوننتی، تعدادی درخواست HTTP به سمت سرور ارسال میشوند که برای دریافت صفحهی index و bundle.js برنامه هستند. اما در برنامههای SPA، مانند جمیل، با هربار کلیک بر روی لینکی، شاهد ریفرش و بارگذاری مجدد کل آن صفحه نیستیم و تنها اطلاعات موجود در قسمت container به روز میشوند.
یک نکته: در اینجا ممکن است دو درخواست websocket و info را نیز مشاهده کنید. این دو مرتبط به hot module reloading هستند که با ذخیرهی برنامه در ادیتور VSCode، بلافاصله سبب به روز رسانی و ریفرش برنامه در مرورگر میشوند.
برای رفع مشکل SPA نبودن برنامه، باید به کامپوننت NavBar مراجعه کرده و تمام anchorهای استاندارد تعریف شدهی در آنرا با کامپوننت Link جایگزین کنیم:
در اینجا ابتدا کامپوننت Link را در ابتدای ماژول، import کردیم. سپس تمام anchorها را یافته و تبدیل به کامپوننت Link نمودیم. همچنین href آنها را نیز به ویژگی to تغییر دادیم.
با این تغییرات اگر برنامه را اجرا کنیم، اینبار با کلیک بر روی هر لینک، دیگر شاهد بارگذاری کامل صفحه در مرورگر نخواهیم بود؛ بلکه تنها قسمت container ای که کامپوننت Route مسیریابی در آن درج شدهاست، به روز رسانی میشود و این عملیات نیز بسیار سریع است؛ از این جهت که محتوای این کامپوننتها از همان bundle.js حاوی تمام کدهای برنامه تامین میشود و این فایل تنها یکبار در آغاز برنامه از سرور خوانده شده و سپس توسط مرورگر پردازش میشود. بنابراین در برنامههای SPA، برخلاف برنامههای وب معمولی، هربار که کاربر آدرس متفاوتی را انتخاب میکند، بارگذاری مجدد برنامه و خوانده شدن محتوای متناظر از سرور صورت نمیگیرد؛ این محتوا هم اکنون در bundle.js برنامه مهیا است و قابلیت استفادهی آنی را دارد.
اما کامپوننت Link چگونه کار میکند؟
کامپوننت لینک در نهایت همان anchorهای استاندارد را رندر میکند؛ اما به هر کدام یک onClick را نیز اضافه میکند که سبب جلوگیری از رفتار پیشفرض anchor میشود. به همین جهت مرورگر درخواست اضافهای را به سمت سرور ارسال نمیکند. در اینجا مدیریت کنندهی onClick، تنها Url بالای صفحه را در مرورگر تغییر میدهد. اکنون که Url تغییر کردهاست، یکی از مسیریابیهای تعریف شده، با این Url تطابق یافته و سپس کامپوننت متناظر با آنرا رندر میکند.
بررسی Route props
اگر بر روی لینک نمایش products در منوی راهبری سایت کلیک کرده و سپس به خروجی افزونهی react developer tools دقت کنیم (تصویر فوق)، مشاهده میکنیم که این کامپوننت هم اکنون تعدادی خاصیت را به صورت props در اختیار دارد؛ مانند history (امکان هدایت کاربر را به صفحهای دیگر دارد)، location (آدرس جاری برنامه) و match (اطلاعاتی در مورد الگوریتم تطابق مسیر). کار تنظیم این props، توسط کامپوننت Route ای که کار ثبت مسیریابیها را انجام میدهد، صورت میگیرد. به عبارتی کامپوننت Route، محصور کنندهی کامپوننتی است که آنرا به عنوان پارامتر، دریافت و در صورت تطابق با مسیر جاری، آنرا رندر میکند. همچنین در این بین کار تزریق خواص props یاد شده را نیز انجام میدهد.
ارسال props سفارشی در حین مسیریابی به کامپوننتها
همانطور که بررسی کردیم، کامپوننت Route، حداقل سه خاصیت props را به کامپوننتهایی که رندر میکند، تزریق خواهد کرد. اما در اینجا برای تزریق خواص سفارشی چگونه باید عمل کرد؟
در حین کار با کامپوننت Route، برای ارسال props اضافی، بجای استفاده از ویژگی component آن، باید از ویژگی render استفاده کرد:
در اینجا کار با تعریف یک arrow function شروع میشود که در نهایت المان کامپوننت مدنظر را همانند روش متداولی که برای تعریف تمام کامپوننتهای React و تنظیم ویژگیهای آنها استفاده میشود، بازگشت میدهد که تاثیر آنرا در خروجی افزونهی react developer tools بهتر میتوان مشاهده کرد:
البته اگر به تصویر فوق دقت کنید، سایر خواص پیشینی که تزریق شده بودند مانند history، location و match، دیگر در اینجا حضور ندارند. برای رفع این مشکل باید تعریف arrow function انجام شده را به صورت زیر تغییر داد:
ابتدا پارامتر arrow function را به همان props تنظیم میکنیم. سپس با استفاده از spread operator، این props را در المان JSX تعریف شده، گسترده و تزریق میکنیم؛ با این خروجی:
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید: sample-15-part-01.zip
برپایی پیشنیازها
در اینجا برای بررسی مسیریابی، یک پروژهی جدید React را ایجاد میکنیم.
> create-react-app sample-15 > cd sample-15 > npm start
> npm install --save bootstrap
import "bootstrap/dist/css/bootstrap.css";
همچنین کتابخانهی ثالث بسیار معروف react-router-dom را نیز نصب میکنیم:
> npm i react-router-dom --save
افزودن مسیریابی به برنامه
پس از نصب کتابخانهی react-router-dom، برای افزودن آن به برنامه و فعالسازی مسیریابی، به فایل index.js مراجعه کرده و import آنرا به ابتدای فایل اضافه میکنیم:
import { BrowserRouter } from "react-router-dom";
ReactDOM.render( <BrowserRouter> <App /> </BrowserRouter>, document.getElementById("root") );
ثبت و معرفی مسیریابیها
در ادامه باید مسیریابیهای خود را ثبت کنیم؛ به این معنا که بر اساس URL خاصی، چه کامپوننتی باید رندر شود. به همین جهت پوشهی جدید src\components را ایجاد کرده و کامپوننت src\components\navbar.jsx را که یک کامپوننت تابعی بدون حالت است، در آن تعریف میکنیم:
import React from "react"; const NavBar = () => { return ( <nav className="navbar bg-dark navbar-dark navbar-expand-sm"> <div className="navbar-nav"> <a className="nav-item nav-link" href="/"> Home </a> <a className="nav-item nav-link" href="/products"> Products </a> <a className="nav-item nav-link" href="/posts/2018/06"> Posts </a> <a className="nav-item nav-link" href="/admin"> Admin </a> </div> </nav> ); }; export default NavBar;
سپس به فایل app.js مراجعه کرده و ساختار آنرا به صورت زیر، جهت درج این NavBar، ویرایش میکنیم تا سبب رندر و نمایش منوی راهبری در مرورگر شود:
import "./App.css"; import React, { Component } from "react"; import NavBar from "./components/navbar"; class App extends Component { render() { return ( <div> <NavBar /> </div> ); } } export default App;
import "./App.css"; import React, { Component } from "react"; import { Route } from "react-router-dom"; import Dashboard from "./components/admin/dashboard"; import Home from "./components/home"; import NavBar from "./components/navbar"; import Posts from "./components/posts"; import Products from "./components/products"; class App extends Component { render() { return ( <div> <NavBar /> <div className="container"> <Route path="/products" component={Products} /> <Route path="/posts" component={Posts} /> <Route path="/admin" component={Dashboard} /> <Route path="/" component={Home} /> </div> </div> ); } } export default App;
کامپوننت جدید src\components\products.jsx جهت رندر لیست آرایهی اشیاء product:
import React, { Component } from "react"; class Products extends Component { state = { products: [ { id: 1, name: "Product 1" }, { id: 2, name: "Product 2" }, { id: 3, name: "Product 3" } ] }; render() { return ( <div> <h1>Products</h1> <ul> {this.state.products.map(product => ( <li key={product.id}> <a href={`/products/${product.id}`}>{product.name}</a> </li> ))} </ul> </div> ); } } export default Products;
کامپوننت بدون حالت تابعی src\components\home.jsx با این محتوا:
import React from "react"; const Home = () => { return <h1>Home</h1>; }; export default Home;
کامپوننت بدون حالت تابعی src\components\posts.jsx با این محتوا:
import React from "react"; const Posts = () => { return ( <div> <h1>Posts</h1> Year: , Month: </div> ); }; export default Posts;
کامپوننت بدون حالت تابعی src\components\admin\dashboard.jsx در پوشهی جدید admin با این محتوا:
import React from "react"; const Dashboard = ({ match }) => { return ( <div> <h1>Admin Dashboard</h1> </div> ); }; export default Dashboard;
معرفی کامپوننت Switch
<div className="container"> <Route path="/products" component={Products} /> <Route path="/posts" component={Posts} /> <Route path="/admin" component={Dashboard} /> <Route path="/" component={Home} /> </div>
یک روش حل این مشکل، استفاده از ویژگی exact است:
<Route path="/" exact component={Home} />
راه دوم رفع این مشکل، استفاده از کامپوننت Switch است. به همین جهت ابتدا این کامپوننت را import میکنیم:
import { Route, Switch } from "react-router-dom";
class App extends Component { render() { return ( <div> <NavBar /> <div className="container"> <Switch> <Route path="/products" component={Products} /> <Route path="/posts" component={Posts} /> <Route path="/admin" component={Dashboard} /> <Route path="/" component={Home} /> </Switch> </div> </div> ); } }
بنابراین هنگام کار با Switch، ترتیب مسیریابیهای تعریف شده مهم است و باید از یک مسیریابی ویژه شروع شده و به یک مسیریابی عمومی مانند / ختم شود.
معرفی کامپوننت Link
تا اینجا اگر برنامه را اجرا کرده باشید و پیشتر سابقهی کار با برنامههای SPA یا Single page applications را داشته باشید، یک مشکل دیگر را نیز احساس کردهاید: سیستم مسیریابی که تا کنون تعریف کردهایم، به صورت SPA عمل نمیکند. یعنی به ازای هربار کلیک بر روی لینکهای منوی راهبری سایت، یکبار دیگر به طور کامل برنامه از صفر بارگذاری مجدد میشود و تمام اسکریپتهای آن مجددا از سرور دریافت شده و رندر خواهند شد. این مورد را در برگهی network ابزارهای توسعه دهندگان مرورگر خود بهتر میتوانید مشاهده کنید. به ازای هر درخواست نمایش کامپوننتی، تعدادی درخواست HTTP به سمت سرور ارسال میشوند که برای دریافت صفحهی index و bundle.js برنامه هستند. اما در برنامههای SPA، مانند جمیل، با هربار کلیک بر روی لینکی، شاهد ریفرش و بارگذاری مجدد کل آن صفحه نیستیم و تنها اطلاعات موجود در قسمت container به روز میشوند.
یک نکته: در اینجا ممکن است دو درخواست websocket و info را نیز مشاهده کنید. این دو مرتبط به hot module reloading هستند که با ذخیرهی برنامه در ادیتور VSCode، بلافاصله سبب به روز رسانی و ریفرش برنامه در مرورگر میشوند.
برای رفع مشکل SPA نبودن برنامه، باید به کامپوننت NavBar مراجعه کرده و تمام anchorهای استاندارد تعریف شدهی در آنرا با کامپوننت Link جایگزین کنیم:
import React from "react"; import { Link } from "react-router-dom"; const NavBar = () => { return ( <nav className="navbar bg-dark navbar-dark navbar-expand-sm"> <div className="navbar-nav"> <Link className="nav-item nav-link" to="/"> Home </Link> <Link className="nav-item nav-link" to="/products"> Products </Link> <Link className="nav-item nav-link" to="/posts/2018/06"> Posts </Link> <Link className="nav-item nav-link" to="/admin"> Admin </Link> </div> </nav> ); }; export default NavBar;
با این تغییرات اگر برنامه را اجرا کنیم، اینبار با کلیک بر روی هر لینک، دیگر شاهد بارگذاری کامل صفحه در مرورگر نخواهیم بود؛ بلکه تنها قسمت container ای که کامپوننت Route مسیریابی در آن درج شدهاست، به روز رسانی میشود و این عملیات نیز بسیار سریع است؛ از این جهت که محتوای این کامپوننتها از همان bundle.js حاوی تمام کدهای برنامه تامین میشود و این فایل تنها یکبار در آغاز برنامه از سرور خوانده شده و سپس توسط مرورگر پردازش میشود. بنابراین در برنامههای SPA، برخلاف برنامههای وب معمولی، هربار که کاربر آدرس متفاوتی را انتخاب میکند، بارگذاری مجدد برنامه و خوانده شدن محتوای متناظر از سرور صورت نمیگیرد؛ این محتوا هم اکنون در bundle.js برنامه مهیا است و قابلیت استفادهی آنی را دارد.
اما کامپوننت Link چگونه کار میکند؟
کامپوننت لینک در نهایت همان anchorهای استاندارد را رندر میکند؛ اما به هر کدام یک onClick را نیز اضافه میکند که سبب جلوگیری از رفتار پیشفرض anchor میشود. به همین جهت مرورگر درخواست اضافهای را به سمت سرور ارسال نمیکند. در اینجا مدیریت کنندهی onClick، تنها Url بالای صفحه را در مرورگر تغییر میدهد. اکنون که Url تغییر کردهاست، یکی از مسیریابیهای تعریف شده، با این Url تطابق یافته و سپس کامپوننت متناظر با آنرا رندر میکند.
بررسی Route props
اگر بر روی لینک نمایش products در منوی راهبری سایت کلیک کرده و سپس به خروجی افزونهی react developer tools دقت کنیم (تصویر فوق)، مشاهده میکنیم که این کامپوننت هم اکنون تعدادی خاصیت را به صورت props در اختیار دارد؛ مانند history (امکان هدایت کاربر را به صفحهای دیگر دارد)، location (آدرس جاری برنامه) و match (اطلاعاتی در مورد الگوریتم تطابق مسیر). کار تنظیم این props، توسط کامپوننت Route ای که کار ثبت مسیریابیها را انجام میدهد، صورت میگیرد. به عبارتی کامپوننت Route، محصور کنندهی کامپوننتی است که آنرا به عنوان پارامتر، دریافت و در صورت تطابق با مسیر جاری، آنرا رندر میکند. همچنین در این بین کار تزریق خواص props یاد شده را نیز انجام میدهد.
ارسال props سفارشی در حین مسیریابی به کامپوننتها
همانطور که بررسی کردیم، کامپوننت Route، حداقل سه خاصیت props را به کامپوننتهایی که رندر میکند، تزریق خواهد کرد. اما در اینجا برای تزریق خواص سفارشی چگونه باید عمل کرد؟
در حین کار با کامپوننت Route، برای ارسال props اضافی، بجای استفاده از ویژگی component آن، باید از ویژگی render استفاده کرد:
<Route path="/products" render={() => <Products param1="123" param2="456" />} />
البته اگر به تصویر فوق دقت کنید، سایر خواص پیشینی که تزریق شده بودند مانند history، location و match، دیگر در اینجا حضور ندارند. برای رفع این مشکل باید تعریف arrow function انجام شده را به صورت زیر تغییر داد:
<Route path="/products" render={props => ( <Products param1="123" param2="456" {...props} /> )} />
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید: sample-15-part-01.zip