React - Lists, Pagination & Filtering

Overview

Estimated time: 25–35 minutes

Display lists with stable keys, filter them by text, and paginate results on the client.

Try it: Filter + Pagination

View source
const { useMemo, useState } = React;
function Pager({ page, pages, onPage }){
  return (
    <div style={{marginTop:8}}>
      <button onClick={() => onPage(Math.max(1, page-1))} disabled={page===1}>Prev</button>
      <span style={{margin:'0 8px'}}>Page {page} / {pages}</span>
      <button onClick={() => onPage(Math.min(pages, page+1))} disabled={page===pages}>Next</button>
    </div>
  );
}
function App(){
  const data = useMemo(() => Array.from({length:50}, (_,i) => ({ id:i+1, name:`Item ${i+1}` })), []);
  const [q, setQ] = useState('');
  const [page, setPage] = useState(1);
  const per = 10;
  const filtered = data.filter(x => x.name.toLowerCase().includes(q.toLowerCase()));
  const pages = Math.max(1, Math.ceil(filtered.length/per));
  const start = (page-1)*per;
  const slice = filtered.slice(start, start+per);
  return (
    <div>
      <input placeholder="Search" value={q} onChange={e => { setQ(e.target.value); setPage(1); }} />
      <ul>{slice.map(x => <li key={x.id}>{x.name}</li>)}</ul>
      <Pager page={page} pages={pages} onPage={setPage} />
      <div style={{marginTop:8, color:'var(--muted)'}}>Total: {filtered.length}</div>
    </div>
  );
}
ReactDOM.createRoot(document.getElementById('try-list')).render(<App />);

Syntax primer

  • Use stable keys (id) for list items.
  • Compute filtered and paginated slices derived from source data.

Common pitfalls

  • Using array index as key can cause incorrect item reuse on reordering.
  • For large lists, consider virtualization libraries.

Exercises

  1. Add page size selector (10/25/50).
  2. Highlight matched search terms.

Checks for Understanding

  1. Why should list items use stable keys instead of array indexes?
  2. What derived state is computed from the source list for filtering and pagination?
  3. Why reset the current page to 1 when the search query changes?
Answers
  1. Stable keys prevent incorrect DOM reuse when inserting/removing/reordering items.
  2. Filtered list (by query), total pages from filtered.length, and the current slice via start/length calculations.
  3. Because the filtered result set may be smaller; staying on a higher page could result in an empty view.