Performance: Fallback UI patterns
Fallback UI patterns affect the perceived loading speed and interaction responsiveness by controlling what the user sees during data fetching or lazy loading.
function MyComponent() { const [data, setData] = React.useState(null); React.useEffect(() => { fetch('/api/data').then(res => res.json()).then(setData); }, []); if (!data) { return <div aria-busy="true" aria-label="Loading content" style={{width: '100%', height: '1rem', backgroundColor: '#eee'}}></div>; } return <div>{data.content}</div>; }
function MyComponent() { const [data, setData] = React.useState(null); React.useEffect(() => { fetch('/api/data').then(res => res.json()).then(setData); }, []); if (!data) { return <div style={{fontSize: '2rem', fontWeight: 'bold'}}>Loading, please wait...</div>; } return <div>{data.content}</div>; }
| Pattern | DOM Operations | Reflows | Paint Cost | Verdict |
|---|---|---|---|---|
| Heavy styled fallback UI | Moderate DOM nodes | Multiple reflows due to size changes | High paint cost from complex styles | [X] Bad |
| Simple fixed-size placeholder fallback | Minimal DOM nodes | Single reflow with fixed size | Low paint cost with simple styles | [OK] Good |
? : correctly chooses between fallback and main UI.{isLoading ? <LoadingSpinner /> : <Content />} uses ternary correctly; B and C misuse logical operators; D uses assignment instead of comparison.{isLoading ? <LoadingSpinner /> : <Content />} [OK]hasError is true?
function MyComponent({ hasError, isLoading }) {
if (hasError) {
return <div>Error occurred</div>
}
if (isLoading) {
return <div>Loading...</div>
}
return <div>Content loaded</div>
}hasError is true.function Profile({ user }) {
return (
<div>
{user ? <ProfileDetails user={user} /> : <LoadingSpinner />}
{!user && <LoadingSpinner />}
</div>
)
}LoadingSpinner if user is falsy.LoadingSpinner if user is falsy, causing it to appear twice when user is falsy.Pass the test and this pattern moves unknown