React / React Lists / Faq’s React List
Home /React /React Lists /Faq’s React List

Faq’s React List

Frequently Asked Questions

Deep-dive answers to the most frequently asked questions about React Lists.

Why do I get a warning saying “Each child in a list should have a unique key prop”?

This React warning appears when you render an array of JSX elements without providing a key prop on each element. React needs keys to efficiently track which items have changed, been added, or been removed. To fix it, add a key attribute to the outermost element returned from your .map() callback. Use a unique, stable value from your data — like a database ID or a slug. Example: <li key={item.id}>{item.name}</li>

Can I use the array index as a key? When is it safe?

Using the index as a key is only safe when all three of these conditions are met: (1) the list is static and never reordered, (2) no items are ever inserted in the middle, and (3) no items are ever deleted. If any of those change, index-as-key causes React to mis-identify items, leading to broken animations, stale state in child inputs, and incorrect UI updates. For any dynamic list — which is most lists in real apps — always use a stable unique ID.

What happens when I use Math.random() as a key?

Using key={Math.random()} is one of the worst anti-patterns in React. Because Math.random() generates a new value on every render, every list item gets a brand new key on every render. React sees these as entirely new elements, and unmounts and remounts the entire list from scratch on every state change. This destroys component-level state (typed values, focus, scroll position), triggers every useEffect with [] on every render, and completely kills performance. Always use stable, predictable keys.

Why can’t I access props.key inside my component?

The key prop is a reserved React attribute — it is consumed entirely by React’s reconciliation system and is never passed through to your component’s props object. Accessing props.key always returns undefined. If your component needs the item’s ID, pass it as a separate explicit prop alongside the key: <Item key={item.id} id={item.id} data={item} />. Then access it via props.id.

Why should I never mutate state arrays directly?

React’s useState hook triggers a re-render only when it detects that the state reference has changed. If you mutate an array directly (e.g., items.push(newItem)), the array reference stays the same, React sees no change, and the UI does not update. You must always return a new array: use spread ([...items, newItem]) to add, .filter() to remove, or .map() to update. This creates a new reference that React detects and re-renders for.

How do I render a list of numbers where 0 is a valid value?

Be careful with the logical AND (&&) operator when your array length or values include 0. For example, {scores.length && <List />} renders “0” when the array is empty because 0 is a valid React child. Fix this by using an explicit boolean comparison: {scores.length > 0 && <List />} or use a ternary: {scores.length ? <List /> : null}. When rendering numbers in list items, they render correctly as {0} appears as “0” in the DOM, which is expected.

How do I handle clicking a specific item in a list?

Wrap the handler in an inline arrow function inside .map() to pass the item’s ID or the item itself: onClick={() => handleSelect(item.id)}. Alternatively, use a data-id attribute: data-id={item.id} and read it in the handler via e.currentTarget.dataset.id. The arrow function approach is more type-safe and idiomatic in modern React. If the item is its own component, pass the handler as a prop.

How do I handle an API that doesn’t return stable IDs?

If your API returns items without unique IDs, add them yourself when you receive the data — before storing in state. Use the uuid library: const items = apiData.map(item => ({ ...item, id: uuidv4() })). Add the IDs once when the data arrives (e.g., in useEffect or your fetch callback) and store the augmented array in state. Do NOT generate the UUID inside .map() during render — that creates a new ID on every render, defeating the purpose.

What is the difference between .map(), .filter(), and .reduce() in list rendering?

.map(item => JSX) — transforms every item into JSX. Output array has the same length as input. Used for rendering. .filter(condition) — removes items that don’t match a condition. Output array is shorter or equal. Used to narrow down what is rendered. .reduce(fn, initial) — accumulates items into a single value (object, number, grouped object). Used to group, count, or reshape data before rendering. In practice, you chain them: data.filter(...).sort(...).map(...).

How do I add a “no results” message when a filtered list is empty?
Filter first, store in a variable, then conditionally render. Example:
const results = courses.filter((c) =>
  c.title.toLowerCase().includes(query)
);

return results.length === 0
  ? <p>No results for "{query}".</p>
  : <ul>{results.map((c) => <li key={c.id}>{c.title}</li>)}</ul>;
How do I render a multi-row table from a data array?
Map over your data array inside <tbody>, returning a <tr> for each item with a unique key:
<table>
  <thead>
    <tr><th>Title</th><th>Level</th></tr>
  </thead>
  <tbody>
    {courses.map((c) => (
      <tr key={c.id}>
        <td>{c.title}</td>
        <td>{c.level}</td>
      </tr>
    ))}
  </tbody>
</table>
What is the key prop on a Fragment and when do I need it?
When a .map() callback returns multiple sibling elements without a wrapper DOM element, you must use <Fragment key={item.id}> (not the shorthand <></>) so that React can track the group as a single keyed unit. This is common in definition lists (<dt>/<dd>), table sections (<tr> pairs), or any case where a wrapper div would break the HTML semantics. The shorthand <></> does not accept the key prop — you must use the explicit <Fragment> import.
How do I render a list from data fetched from an API?

Use useState for the data, loading, and error states, and useEffect to fetch on mount. Always handle loading and error before rendering the list:

const [data, setData]       = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError]     = useState(null);

useEffect(() => {
  fetch('/api/courses')
    .then((r) => r.json())
    .then(setData)
    .catch(setError)
    .finally(() => setLoading(false));
}, []);

if (loading) return <Spinner />;
if (error)   return <p>Error loading data.</p>;
return <ul>{data.map((c) => <li key={c.id}>{c.title}</li>)}</ul>;
When should I extract list items into separate components?
Extract a list item into its own component when: (1) the item JSX spans more than 3–4 lines, (2) the item has its own internal state (expanded/collapsed, hover effect, form), (3) you want to apply React.memo optimization so items only re-render when their own data changes, (4) the same item structure is reused in multiple places in your app, or (5) you want to write unit tests for the item in isolation. For simple 1-2 line items like <li key={x.id}>{x.name}</li>, keeping it inline is perfectly fine.
How do I build a drag-and-drop reorderable list in React?

For drag-and-drop lists, use a dedicated library rather than building from scratch. The most popular options are: dnd kit (@dnd-kit/core) — modern, accessible, and highly customizable; react-beautiful-dnd — widely used, great defaults, but archived by Atlassian; and react-sortable-hoc — HOC-based. The pattern: (1) wrap your list in a drag context, (2) make each item draggable and define a drop target, (3) on drag end, reorder your state array using the arrayMove utility and call setItems(reorderedArray). Keys are critical here — they must be stable IDs, never indices, so React correctly tracks elements during reordering.