فهرست
مقدمه
صفحه ۱دانلود و نمایش دمو
نصب و اجرا
ویرایش و توسعه
جزییات نصب و اجرا ـ ۱
صفحه ۲عملیات Build
Start پروژه
جزییات نصب و اجرا ـ ۲
صفحه ۳استفاده از Node Stream
آمادهسازی Router
ارتباط با API
صفحه ۴تابع FetchData و پارامترهای آن
تابع API و پارامترهای آن
ارتباط کامپوننتهای React با دادههای API
صفحه ۵پیادهسازی Loading
صفحه ۶پیادهسازی تگهای سرصفحه
صفحه ۷پیادهسازی نقشهی سایت XML
صفحه ۸
در صفحههای قبلی، نحوهی دریافت، نصب و اجرا ، توسعهی پروژه، جزییات نصب و اجرای پروژه، ارتباط با API و همچنین نحوهی ارتباط کامپوننتهای React با دادههای دریافتی از API توضیح داده شد. در این صفحه به سراغ نحوهی پیادهسازی Loading، میرویم.
پیادهسازی Loading
پیادهسازی Loading و Lazy loading در کامپوننتهای React با استفاده از Suspense و lazy بهراحتی امکان پذیر است.
اما اگر قصد فراخوانی کامپوننتی به شکل Suspense را داریم که دادههایی را از منبع API، دریافت میکند، آن دادههای دریافتی در HTML سمت سرور ما، قرار نخواهند گرفت.
البته این مشکل هنگام پیادهسازی SSR در فریمورک Next.js وجود ندارد، اما در فریمورک Express.js و هنگام استفاده از renderToPipeableStream در نسخهی 18.2.0 React، که رندرینگ سمت سرور این پروژه در چارچوب آنها نوشته شده، باید راه دیگری را برای پیادهسازی Loading در نظر گرفت که در ادامه به توضیح آن خواهیم پرداخت.
در این لینک(انتهای Note آخر) توضیح داده شده که «در نسخهی بعدی React، مسالهی ادغام منابع API در
Suspenseبه وسیلهی یک Server API جدید حل خواهد شد.»
لازم به ذکر است که برای هر کامپوننتی که قصد دریافت دادهها از منبع API در آنها را نداریم، همچنان میتوانیم از Suspense و Lazy loading در همین پروژه نیز استفاده کنیم.
برای پیادهسازی Loading در این پروژه، ابتدا در کامپوننت موردنظر یک State با نام loading و با تایپ boolean تعریف میکنیم .
مقدار اولیهی loading را طوری تعیین میکنیم که:
اگر اندازهی آبجکت دریافتی درون dataFromServer.['firstData'] صفر نبود، مقدار loading برابر با false باشد.
و اگر اندازهی آبجکت دریافتی درون dataFromServer.['firstData'] صفر بود، مقدار loading برابر با true باشد.
import { useState } from "react";
const Category = ({ dataFromServer }) => {
const [loading, setLoading] = useState((Object.keys(dataFromServer?.['firstData'])?.length !== 0) ? false : true);
.
.
حالا از loading، درون کامپوننتمان، به شکل زیر میتوانیم استفاده کنیم.
اگر true باشد Loading... Please Wait به کاربر نمایش داده میشود و اگر false باشد، اجزای دلخواه دیگر به همراه مقادیر دریافت شده از منبع API.
import { useState } from "react";
const Category = ({ dataFromServer }) => {
const [data, setData] = useState(dataFromServer?.['firstData'] || []);
const [loading, setLoading] = useState((Object.keys(dataFromServer?.['firstData'])?.length !== 0) ? false : true);
return (
<>
{loading && "Loading... Please Wait"}
{!loading && data?.map((_v, _i) => {return ({<h1>_v?.title</h1>})})}
</>
)
اگر فرض بگیریم که ورود کاربر به این کامپوننت مستقیم بوده باشد، به همین دلیل دادههای منبع API، پیشاپیش از طریق تابع render (فایل server.mjs) درون آبجکت dataFromServer.['firstData'] قرار گرفته است؛ پس dataFromServer.['firstData'] خالی نیست و مقدار loading برابر با false خواهد بود. در اینصورت کامپوننت ما بدون نمایش Loading... Please Wait با مقادیر دریافت شده از منبع API به همراه اجزای دیگرِ صفحه، به کاربر نمایش داده خواهد شد و همهی اینها به درستی در سورس HTML سمت سرور نیز، وجود خواهند داشت.
اما اگر dataFromServer?.['firstData'] خالی باشد، یعنی ورود کاربر به این Route مستقیم نبوده و یا اینکه اگر هم مستقیم بوده، به هر دلیلی دادهیی از منبع API از قبل و در هنگام عملیات رندرینگ دریافت نشده است. پس مقدار loading در این صورت برابر با true خواهد بود، و تا زمانی که ما مقدار آن را false نکرده باشیم Loading... Please Wait به کاربر نمایش داده خواهد شد.
در اینصورت، پس از اینکه تابع FetchData را درون هوک useEffect فراخوانی کردیم(خط۱۱) و دادههای مربوطه را از منبع API دریافت کردیم، میتوانیم دادههای دریافتی را درون data با setData() قرار دهیم(خط۱۲) ؛ و پس از آن، مقدار loading را با setLoading()(خط۱۳) برابر با false میکنیم تا Loading... Please Wait پنهان شود؛ و اجزای مورد نظرمان به همراه مقادیر دریافتی از منبع API به کاربر نمایش داده شود.
import { useState, useEffect } from "react";
import FetchData from "../../core/FetchData.mjs";
const Category = ({ dataFromServer }) => {
const [data, setData] = useState(dataFromServer?.['firstData'] || []);
const [loading, setLoading] = useState((Object.keys(dataFromServer?.['firstData'])?.length !== 0) ? false : true);
let response;
useEffect(() => {
if (Object.keys(dataFromServer?.['firstData'])?.length === 0)
(async () => {
response = await FetchData('get', 'https://api_URL');
setData(response);
setLoading(false);
})()
dataFromServer['firstData'] = {};
}, []);
return (
<>
{loading && "Loading... Please Wait"}
{!loading && (data?.length !== 0) && data?.map((_v, _i) => {return ({<h1>_v?.title</h1>})})}
</>
)
}
نکته مهم: دادههایی که توسط تابع render (فایل server.mjs) به کامپوننتها منتقل شدهاند و در آبجکت dataFromServer[firstData] قرار گرفتهاند، باید بدون ایجاد عمدی تاخیر، در کامپوننتها وارد شده باشند. مثلا اگر در هوک useEffect که بعد از رندر اولیه فراخوانی خواهد شد، دادههای آبجکت dataFromServer[firstData] را set کنیم یا به هر طریقی، تاخیر در انتقال دادههای آبجکت dataFromServer[firstData] به کامپوننتها ایجاد کنیم، دادههای منبع API در خروجی HTML سمت سرور، وجود نخواهند داشت.
صفحهی قبل: ارتباط کامپوننتهای React با دادههای API
صفحهی بعد: پیادهسازی متاتگها
اطلاعات برنامه
نام: express-react-ssr
پلتفرم: Node.js
زبان: JavaScript
لایسنس: MIT
تاریخ انتشار اولیه: ۹ مرداد ۱۴۰۳
تاریخ آخرین بهروزرسانی: ۱۱ شهریور ۱۴۰۳
مخزن: GitHub