LoadingState appears only after 300ms: fast API answers no longer flash the loader (packs screen and every other data screen)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -67,21 +67,6 @@ export function MainApp({ profile, grades, payment, onSignedOut }: Props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* صفحهها از قبل گرفته شدهاند، ولی `lazy` حتی برای ماژولِ آماده هم یک رندرِ تهی میگیرد؛ نشان دادنِ
|
|
||||||
* «یه لحظه صبر کن» در همان یک-دو فریم همان پرشِ ریزِ بینِ صفحهها بود. لودر فقط اگر بارگیری
|
|
||||||
* واقعاً طول کشید (شبکهی کند، پیش از تمام شدنِ preload) پس از ۳۰۰ms ظاهر میشود.
|
|
||||||
* با مرورگر دیده نشده؛ فقط از روی کد.
|
|
||||||
*/
|
|
||||||
function DelayedLoading() {
|
|
||||||
const [show, setShow] = useState(false);
|
|
||||||
useEffect(() => {
|
|
||||||
const t = setTimeout(() => setShow(true), 300);
|
|
||||||
return () => clearTimeout(t);
|
|
||||||
}, []);
|
|
||||||
return show ? <LoadingState /> : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Screens({ onSignedOut }: Pick<Props, 'onSignedOut'>) {
|
function Screens({ onSignedOut }: Pick<Props, 'onSignedOut'>) {
|
||||||
const nav = useNav();
|
const nav = useNav();
|
||||||
const { route } = nav;
|
const { route } = nav;
|
||||||
@@ -99,7 +84,7 @@ function Screens({ onSignedOut }: Pick<Props, 'onSignedOut'>) {
|
|||||||
exit={{ opacity: 0, x: 18 }}
|
exit={{ opacity: 0, x: 18 }}
|
||||||
transition={{ duration: 0.18 }}
|
transition={{ duration: 0.18 }}
|
||||||
>
|
>
|
||||||
<Suspense fallback={<DelayedLoading />}>
|
<Suspense fallback={<LoadingState />}>
|
||||||
<RouteView route={route} onSignedOut={onSignedOut} />
|
<RouteView route={route} onSignedOut={onSignedOut} />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { ButtonHTMLAttributes, CSSProperties, ReactNode } from 'react';
|
import { useEffect, useState, type ButtonHTMLAttributes, type CSSProperties, type ReactNode } from 'react';
|
||||||
import { ChevronRight, RotateCw } from 'lucide-react';
|
import { ChevronRight, RotateCw } from 'lucide-react';
|
||||||
import { SeyarMascot } from '@/mascots/SeyarMascot';
|
import { SeyarMascot } from '@/mascots/SeyarMascot';
|
||||||
import type { SeyarChar, SeyarMood } from '@/mascots/seyar';
|
import type { SeyarChar, SeyarMood } from '@/mascots/seyar';
|
||||||
@@ -130,8 +130,19 @@ function StateBox({ char, mood, text, children }: { char: SeyarChar; mood: Seyar
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function LoadingState({ text = 'یه لحظه صبر کن…', char = 'sigma' as SeyarChar }) {
|
/**
|
||||||
return <StateBox char={char} mood="idle" text={text} />;
|
* لودر فقط بعد از `delayMs` دیده میشود. پاسخِ API معمولاً زیرِ ۳۰۰ms میرسد و نشان دادنِ لودر برای
|
||||||
|
* همان چند فریم، پرشِ ریزِ «لودر ← محتوا» میساخت؛ حالا تا آن لحظه جای خالی میماند. اگر پاسخ
|
||||||
|
* کند باشد کاربر باز هم لودر را میبیند. در مرورگر با شبکهی کند آزموده نشده.
|
||||||
|
*/
|
||||||
|
export function LoadingState({ text = 'یه لحظه صبر کن…', char = 'sigma' as SeyarChar, delayMs = 300 }) {
|
||||||
|
const [show, setShow] = useState(delayMs <= 0);
|
||||||
|
useEffect(() => {
|
||||||
|
if (delayMs <= 0) return;
|
||||||
|
const t = setTimeout(() => setShow(true), delayMs);
|
||||||
|
return () => clearTimeout(t);
|
||||||
|
}, [delayMs]);
|
||||||
|
return show ? <StateBox char={char} mood="idle" text={text} /> : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ErrorState({ error, onRetry, text }: { error?: unknown; onRetry?: () => void; text?: string }) {
|
export function ErrorState({ error, onRetry, text }: { error?: unknown; onRetry?: () => void; text?: string }) {
|
||||||
|
|||||||
Reference in New Issue
Block a user