mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
- Remove nested git repository from bugulma/frontend/.git - Add all frontend files to main repository tracking - Convert from separate frontend/backend repos to unified monorepo - Preserve all frontend code and development history as tracked files - Eliminate nested repository complexity for simpler development workflow This creates a proper monorepo structure with frontend and backend coexisting in the same repository for easier development and deployment.
6.6 KiB
6.6 KiB
Async Rendering Guide
Overview
All pages and components are designed to render asynchronously - they never block on API requests. Components render immediately with loading states or placeholder data, and data updates asynchronously as it arrives from the backend.
Key Principles
1. Non-Blocking Rendering
- Components render immediately, even before API data arrives
- Use
placeholderDatain React Query hooks to provide safe defaults - Never wait for API responses before rendering
2. Progressive Data Loading
- Initial render shows loading states or empty states
- Data updates asynchronously as API responses arrive
- Multiple API calls happen in parallel, not sequentially
3. Safe Defaults
- All hooks return safe default structures (empty arrays, undefined, etc.)
- Components handle
undefinedandnullgracefully - No assumptions about data structure
Implementation Patterns
React Query Hooks with placeholderData
All useQuery hooks include placeholderData to prevent blocking:
// ✅ Good - Renders immediately with empty array
export function useOrganizations() {
return useQuery({
queryKey: organizationKeys.lists(),
queryFn: getOrganizations,
placeholderData: [], // Component renders immediately
staleTime: 30 * 1000,
});
}
// ✅ Good - Renders immediately with undefined
export function useOrganization(id: string | null | undefined) {
return useQuery({
queryKey: organizationKeys.detail(id!),
queryFn: () => getOrganizationById(id!),
enabled: !!id,
placeholderData: undefined, // Component handles undefined
});
}
Component Pattern
Components should handle placeholder data gracefully:
// ✅ Good - Handles placeholder data
const MyComponent = () => {
const { data, isLoading } = useOrganizations();
// placeholderData ensures data is always an array
const organizations = Array.isArray(data) ? data : [];
// Render immediately, show loading only if no placeholder data
if (isLoading && organizations.length === 0) {
return <LoadingSpinner />;
}
return <div>{/* Render with data */}</div>;
};
Safe Array Operations
Always check arrays before operations:
// ✅ Good - Safe array operations
const items = Array.isArray(data?.items) ? data.items : [];
const filtered = items.filter(item => item?.id);
const mapped = items.map(item => ({ ...item }));
// ❌ Bad - Assumes data is always an array
const items = data.items; // Could be undefined
items.filter(...); // Crashes if undefined
Hooks Updated
All API hooks now include placeholderData:
Organizations
useOrganizations()-placeholderData: []useOrganization(id)-placeholderData: undefineduseUserOrganizations()-placeholderData: []
Sites
useSite(id)-placeholderData: undefineduseSitesByOrganization(id)-placeholderData: []useNearbySites(query)-placeholderData: []
Resource Flows
useResourceFlow(id)-placeholderData: undefineduseResourceFlowsBySite(id)-placeholderData: []useResourceFlowsByOrganization(id)-placeholderData: []
Proposals
useProposals()-placeholderData: { proposals: [] }useProposal(id)-placeholderData: undefineduseProposalsForOrganization(id)-placeholderData: { incoming: [], outgoing: [] }
Matching
useDirectSymbiosis(id)-placeholderData: { providers: [], consumers: [] }useFindMatches(id)-placeholderData: { matches: [] }
Analytics
useConnectionStatistics()-placeholderData: { total_connections: 0 }useSupplyDemandAnalysis()-placeholderData: { supply: [], demand: [] }useDashboardStatistics()-placeholderData: { total_organizations: 0, recent_activity: [] }
Benefits
- Instant Rendering: Pages render immediately, no waiting for APIs
- Better UX: Users see loading states or empty states right away
- No Freezing: Components never block on API requests
- Progressive Enhancement: Data appears as it loads
- Error Resilience: Safe defaults prevent crashes
Testing
To verify async rendering:
- Network Throttling: Use DevTools to throttle network to "Slow 3G"
- Check Rendering: Page should render immediately with loading states
- Verify Updates: Data should appear as API responses arrive
- Test Empty States: Disable network to see empty state handling
Common Patterns
Pattern 1: List with Loading State
const { data, isLoading } = useOrganizations();
const items = Array.isArray(data) ? data : [];
if (isLoading && items.length === 0) {
return <LoadingSpinner />;
}
return <List items={items} />;
Pattern 2: Detail with Placeholder
const { data, isLoading } = useOrganization(id);
if (isLoading && !data) {
return <Skeleton />;
}
if (!data) {
return <NotFound />;
}
return <Detail data={data} />;
Pattern 3: Parallel Loading
// Multiple queries load in parallel
const { data: org } = useOrganization(id);
const { data: sites } = useSitesByOrganization(id);
const { data: flows } = useResourceFlowsByOrganization(id);
// All render immediately with placeholderData
// Updates happen asynchronously as data arrives
Anti-Patterns to Avoid
❌ Blocking on Data
// Bad - Blocks render until data arrives
const { data } = useOrganizations();
if (!data) return null; // Blocks render
❌ Unsafe Array Operations
// Bad - Crashes if data is undefined
const items = data.items;
items.map(...); // Error if items is undefined
❌ Synchronous Operations in Render
// Bad - Blocks render
const processed = heavyComputation(data); // Blocks
Performance Considerations
- placeholderData is lightweight - just empty arrays/objects
- React Query handles caching and deduplication
- Components re-render only when data actually changes
- Memoization prevents unnecessary recalculations
Migration Checklist
- All
useQueryhooks haveplaceholderData - Components handle
undefinedandnullsafely - Array operations are guarded with
Array.isArray() - Loading states show only when no placeholder data exists
- Error states don't block rendering
- Context providers don't block on data
Future Improvements
- Suspense Boundaries: Consider React Suspense for better loading UX
- Optimistic Updates: Update UI immediately, rollback on error
- Streaming: For large datasets, consider streaming responses
- Prefetching: Prefetch data before navigation