-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
Overview
Build the traditional React SSR with client-side data fetching version.
Dependency: Task 2 (Shared Components & API)
Can Run Parallel With: Task 4 (RSC Version)
Key Architecture
"use client"at root level → all components become client components- Components go into the client bundle (NOT RSC bundle)
- Static parts SSRed, but lazy-loaded components are NOT SSRed
- Only Suspense fallbacks (spinners) render on server for lazy components
- Data fetches client-side via
useEffect/fetch
Deliverables
Rails View
<!-- app/views/restaurants/search.html.erb -->
<div class="search-page">
<%= react_component("SearchPage", { restaurant_id: @restaurant.id }) %>
</div>Components
| Component | Type | Purpose |
|---|---|---|
SearchPage.tsx |
Entry | SSRed by react_component helper |
SearchPageContent.tsx |
Client ("use client") |
Main content with hooks |
AsyncStatus.tsx |
Lazy-loaded | Fetches status client-side |
AsyncWaitTime.tsx |
Lazy-loaded | Fetches wait time client-side |
AsyncSpecials.tsx |
Lazy-loaded | Fetches specials client-side |
AsyncTrending.tsx |
Lazy-loaded | Fetches trending client-side |
AsyncRating.tsx |
Lazy-loaded | Fetches rating client-side |
Pattern
// SearchPageContent.tsx
"use client";
import { Suspense, lazy } from 'react';
const AsyncStatus = lazy(() => import('./AsyncStatus'));
export function SearchPageContent({ restaurantId }: Props) {
return (
<Suspense fallback={<Spinner />}>
<AsyncStatus restaurantId={restaurantId} />
</Suspense>
);
}
// AsyncStatus.tsx (lazy-loaded, NOT SSRed)
export default function AsyncStatus({ restaurantId }: Props) {
const [status, setStatus] = useState(null);
useEffect(() => {
fetch(`/api/restaurants/${restaurantId}/status`)
.then(r => r.json())
.then(setStatus);
}, [restaurantId]);
return status ? <StatusBadge status={status} /> : null;
}Performance Monitoring
- Collect Web Vitals (LCP, CLS, INP)
- Measure "Lazy Load Time" (mount to display)
Success Criteria
-
/searchpage loads and renders - Static parts SSR completely
- Spinners show while loading (lazy components NOT SSRed)
- Lazy components load in separate chunks
- API calls visible in DevTools Network tab
- LCP: ~500-600ms
- CLS: ~0.10-0.15
- Console shows no errors
Expected Timeline
0-50ms: SSRed HTML received (spinners visible)
50-100ms: JS bundles download
100-150ms: React hydrates
150-200ms: Lazy components load, useEffect fires
200-350ms: API requests in flight
350-500ms: Responses received, spinners replaced
500-600ms: All content visible (LCP)
Key Files to Create
app/javascript/entries/search.tsx
app/javascript/components/search/SearchPage.tsx
app/javascript/components/async/traditional/
├─ SearchPageContent.tsx
├─ AsyncStatus.tsx
├─ AsyncWaitTime.tsx
├─ AsyncSpecials.tsx
├─ AsyncTrending.tsx
└─ AsyncRating.tsx
app/views/restaurants/search.html.erb
coderabbitai
Metadata
Metadata
Assignees
Labels
No labels