هنگام رفرش یا وارد کردن دستی آدرس ها در React-router کار نمی کنند
مشکل عدم کارکرد صحیح URL ها در React-router هنگام رفرش یا وارد کردن دستی آدرس، به دلیل تفاوت در نحوه تفسیر URL در سمت سرور و سمت کلاینت است. در گذشته، تنها سرور URL را تفسیر میکرد و در پاسخ، صفحه مربوطه را ارسال مینمود. اما با استفاده از روتینگ سمت کلاینت در React-router، فرآیند پیچیدهتر میشود.
در اولین درخواست، سرور صفحه اولیه (که شامل اسکریپتهای لازم برای بارگذاری React و React-router است) را ارسال میکند. پس از بارگذاری این اسکریپتها، روتینگ سمت کلاینت توسط React-router انجام میگیرد. کلیک بر روی لینکها باعث تغییر URL در نوار آدرس (بدون رفرش صفحه) میشود و React-router صفحه مربوطه را رندر میکند. این تغییر URL تنها در سمت کلاینت انجام میشود و نیازی به درخواست مجدد از سرور نیست مگر اینکه صفحه نیاز به دریافت اطلاعات از سرور (مثلا از طریق REST API) داشته باشد.
اما اگر URL به صورت دستی در نوار آدرس وارد یا از طریق ایمیل به اشتراک گذاشته شود، سرور درخواست را دریافت میکند، زیرا در این حالت هنوز کد جاوااسکریپت و React-router بارگذاری نشدهاند. در این مواقع، اگر سرور آدرس مورد نظر را تشخیص ندهد، خطای 404 نمایش داده میشود.
برای حل این مشکل، چندین راه حل وجود دارد:
1. استفاده از Hash History: با استفاده از Hash History، بخش URL بعد از علامت # به سرور ارسال نمیشود و سرور تنها صفحه index را ارسال میکند. React-router بخش بعد از # را تفسیر میکند. این روش URL ها را کمتر خوانا میکند (مثلا http://example.com/#/about).
2. استفاده از Catch-all Route در سرور: در این روش، از Browser History استفاده میشود اما یک مسیر Catch-all در سرور تعریف میشود که هر درخواستی به index.html هدایت میکند. این روش URLهای خوانایی را فراهم میکند اما نیاز به تنظیمات بیشتری در سرور دارد و باید از intercept کردن درخواستهای فایلهای CSS و JS جلوگیری کرد. برای سرورهای Apache میتوانید از .htaccess استفاده کنید:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule . /index.html [L]
</IfModule>
3. استفاده از اگر از Webpack استفاده میکنید، میتوانید از گزینه historyApiFallback: true در تنظیمات devServer استفاده کنید. این گزینه باعث میشود Webpack درخواستهای نامعتبر را به index.html هدایت کند. این روش مناسب توسعه است اما برای محیط تولید توصیه نمیشود. این گزینه را می توان از طریق خط فرمان با پرچم --history-api-fallback نیز تنظیم کرد.
devServer: {
historyApiFallback: true,
contentBase: './',
hot: true
},
4. رندر ایزومورفیک (Isomorphic Rendering): این روش پیشرفتهترین و ایدهآلترین روش است. در این روش، از یک کد جاوااسکریپت هم در سمت سرور و هم در سمت کلاینت استفاده میشود. سرور همان markup را ارسال میکند که در صورت رندر شدن در سمت کلاینت تولید میشد. این روش بهینه ترین حالت برای SEO است. برای استفاده از این روش به یک سرور مبتنی بر Node.js نیاز دارید.
انتخاب روش مناسب به نیازها و فناوریهای مورد استفاده بستگی دارد. اگر از سرورهای ساده استفاده میکنید، روش Catch-all و یا historyApiFallback گزینه های مناسبی هستند. در صورتی که از Node.js استفاده میکنید، رندر ایزومورفیک میتواند بهترین گزینه باشد. همچنین استفاده از starter kit ها میتواند به شروع کار کمک کند. فراموش نکنید که React تنها بخش View در MVC است و برای توسعه یک اپلیکیشن کامل به اجزای دیگر نیاز دارید.