
فهرست
مقدمه
صفحه ۱دانلود و نمایش دمو
نصب و اجرا
ویرایش و توسعه
جزییات نصب و اجرا ـ ۱
صفحه ۲عملیات 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