React - Collection Grid with Pagination
Overview
Estimated time: 20–30 minutes
Render a card grid with fixed-height thumbnails and responsive wrapping, plus pagination controls.
Try it: Card grid
View source
function Grid({items}){
return (
<div style={{display:'grid', gridTemplateColumns:'repeat(auto-fill, minmax(140px, 1fr))', gap:12}}>
{items.map((it) => (
<article key={it.id} style={{border:'1px solid var(--border)', borderRadius:8, overflow:'hidden'}}>
<div style={{height:100, background:'#eee'}}><img alt="" loading="lazy" src={`https://picsum.photos/seed/${it.id}/300/200`} style={{width:'100%', height:'100%', objectFit:'cover'}} /></div>
<div style={{padding:8}}>
<h4 style={{margin:'4px 0'}}>{it.title}</h4>
<p style={{margin:0, color:'#666'}}>{it.subtitle}</p>
</div>
</article>
))}
</div>
);
}
function Pager({page, pages, onChange}){
return (<div style={{display:'flex', gap:8, justifyContent:'center', marginTop:8}}>
<button onClick={()=> onChange(page-1)} disabled={page===1}>Prev</button>
<span>Page {page} / {pages}</span>
<button onClick={()=> onChange(page+1)} disabled={page===pages}>Next</button>
</div>);
}
function App(){
const all = Array.from({length:48}, (_,i)=> ({id:i+1, title:`Card ${i+1}`, subtitle:'Example subtitle'}));
const perPage = 12; const [page, setPage] = React.useState(1);
const pages = Math.ceil(all.length/perPage); const start=(page-1)*perPage;
const items = all.slice(start, start+perPage);
return (<div>
<Grid items={items} />
<Pager page={page} pages={pages} onChange={setPage} />
</div>);
}
ReactDOM.createRoot(document.getElementById('try-grid-pag')).render(<App />);
Syntax primer
- Use CSS grid with auto-fill and minmax for responsive wrapping.
- Keep thumbnails same height via a fixed container and object-fit: cover.
Common pitfalls
- Layout shift due to images loading—reserve space with fixed height.
Exercises
- Add a selectable card state and show selected count.
- Persist the current page in the hash or query string.
Checks for Understanding
- Why use object-fit: cover inside a fixed-height container for thumbnails?
- How do you compute which items to render for the current page?
- What are the tradeoffs of client-side pagination on large datasets?
Answers
- It preserves aspect ratio while filling the box, preventing layout shift from varying image sizes.
- Calculate pages = ceil(total/perPage), start = (page-1)*perPage, then slice(all, start, start+perPage).
- It’s simple and fast for small lists but requires loading all data; for large datasets use server-side pagination or virtualization.