Why the "Popular" Marquee Across Three Pillars Looks Empty — and How to Fill It
Marquee populer 3 pilar (olahraga/kebudayaan/kepemudaan) kosong di pilar muda. Fix: parallel fetch popular + random, mergePopularWithRandom dedupe by id, popular priority, slice 9.
TL;DR
KotaPortal's marquee looked half-empty. Server-side parallel fetch and merge dedupe fixed this. Young pillars now display 9 items.
The Problem: Young Pillars, Half-Empty Marquees
I opened the olahraga, kebudayaan, and kepemudaan pages on KotaPortal and each had a vertical "Popular" marquee. But the newer pillars — like kepemudaan — only had 3-4 popular items. The marquee looked half-empty, which looks broken.
The Fix: Parallel Fetch + Merge Dedupe Server-Side
Commit a5f93eb fixes this with a server-side parallel fetch + merge dedupe pattern. Each pillar fetches two things in parallel: sort=popular (limit 9) + sort=random (limit 9, presentation=visual). Then mergePopularWithRandom combines them: popular first, dedupe by id, slice to 9. The marquee stays full at 9 items even for young pillars.
Why Parallel Fetch?
Next.js says parallel data fetching reduces waterfalls and total load time [4]. Sequential would make random wait for popular — wasted time.
Merge Logic
The merge lives in a server component (populer.ts), not the client. Map-based merge: existing entities (popular) never overwritten, novel entities (random) appended [5]. Dedupe by id prevents duplicates. Popular priority — if an item exists in both lists, the popular version wins.
function mergePopularWithRandom(popular: Item[], random: Item[]): Item[] {
const seen = new Set()
const merged: Item[] = []
for (const item of popular) {
if (!seen.has(item.id)) {
seen.add(item.id)
merged.push(item)
}
}
for (const item of random) {
if (!seen.has(item.id) && merged.length < 9) {
seen.add(item.id)
merged.push(item)
}
}
return merged
}Next.js RSC executes sequentially within a tree [6]. But here we fetch inside one server component (page.tsx), so Promise.all([fetchPopular(), fetchRandom()]) runs in parallel. No component restructure needed.
Test Coverage
populer.test.ts covers merge logic (popular priority, dedupe, slice 9, empty cases). All green.
Sources
- Next.js: Parallel data fetching reduces waterfalls
- FrontendCache: Map-based merge utility for idempotent dedupe
- Vercel: RSC execute sequentially; restructure with composition for parallel fetch