3.6 KiB
3.6 KiB
Lazy Loading Card Table
Date
2026-08-14
Goal
Optimize page load performance for raw materials, products, purchases, and cutting list pages by implementing lazy loading for child/variant data in card-based layouts.
Problem
Pages with 100+ records loaded all child data eagerly (variants, items, materials), causing slow initial page loads.
Solution Pattern
- Backend: Remove eager-loaded relationships from paginated query
- Backend: Add SQL subqueries for summary data (
variants_count,total_qty,material_name,unit,materials_count,total_usage,product_name,cutting_result) - Backend: Add new controller method returning JSON for lazy load
- Frontend: Use
useCardTableExpand(false)for default collapsed state - Frontend: Fetch child data via
fetch()on expand, store inRecord<number, T[]>state - Frontend: Pass
items+isLoadingprops to sub-row components
Files Modified
Cutting (this session)
app/Services/Admin/Manage/CuttingService.php-paginated()no longer eager loadscuttingResults,cuttingMaterials,cuttingMaterialCombinations; addedgetMaterials()andgetCombinations()methodsapp/Http/Controllers/Admin/Manage/CuttingController.php- addedmaterials()methodroutes/web.php- addedGET cuttings/{cutting}/materialsrouteresources/js/pages/admin/manage/cutting/columns.tsx-Cuttingtype:materials_count,total_usage,product_name,cutting_resultresources/js/pages/admin/manage/cutting/cutting-card.tsx- uses summary data from propsresources/js/pages/admin/manage/cutting/cutting-sub-row.tsx- acceptsmaterials,combinations,isLoadingpropsresources/js/pages/admin/manage/cutting/index.tsx- lazy loading withfetchMaterials()resources/js/pages/admin/manage/cutting/show.tsx- passes full data to sub-row
Purchases (this session)
app/Services/Admin/Manage/PurchaseService.php-paginated()no longer eager loadspurchaseItems; addedgetItems()methodapp/Http/Controllers/Admin/Manage/PurchaseController.php- addeditems()methodroutes/web.php- addedGET purchases/{purchase}/itemsrouteresources/js/pages/admin/manage/purchase/columns.tsx-Purchasetype:variants_count,total_qty,material_name,unitresources/js/pages/admin/manage/purchase/purchase-card.tsx- uses summary data from propsresources/js/pages/admin/manage/purchase/purchase-sub-row.tsx- acceptsitems&isLoadingpropsresources/js/pages/admin/manage/purchase/index.tsx- lazy loading withfetchItems()
Raw Materials & Products (previous sessions)
- Same pattern applied to
RawMaterialService,RawMaterialController,ProductService,ProductController - Frontend pages updated with lazy loading state
Routes Added
Route::get('purchases/{purchase}/items', [PurchaseController::class, 'items'])->name('purchases.items')->middleware('permission:purchases.view');
Route::get('cuttings/{cutting}/materials', [CuttingController::class, 'materials'])->name('cuttings.materials')->middleware('permission:cuttings.view');
Key Implementation Details
- SQL subqueries avoid N+1 queries while keeping summary data in the paginated response
getItems()/getMaterials()/getCombinations()methods handle media URL resolution for photos- Frontend caches loaded items to avoid re-fetching on repeated expand/collapse
- Loading state shown while items are being fetched
- Show pages (e.g.,
show.tsx) pass full data directly to sub-row components
Verification
- PHP syntax check: OK
- TypeScript: Only pre-existing errors in
use-*-draft.tsfiles (unrelated) - Route cache cleared