How to Loop Over an Array or Array of Objects in React

Beginner8 min interview
Skills tested:
Using map() to transform an array of data into an array of JSX elementsUsing a stable unique key on each element returned from map()Using filter() with map() to render only matching itemsHandling the empty array case with an early return or ternaryUsing flatMap() to flatten and map nested arrays in one pass

Advertisement

🧩 Scenario

Rendering lists from data is in every React component: product cards from an API, messages in a chat, rows in a table, options in a dropdown. map() is the primary tool, and knowing how to combine it with filter(), handle the empty state, and apply stable keys correctly is essential for any React interview.

Architecture Walkthrough

map() as the Primary List Rendering Tool

React renders lists by returning an array of JSX elements. map() transforms each item in a data array into a JSX element, returning a new array that React renders in order. Because map() is an expression that produces a value, it can be used directly inside JSX curly braces, unlike for or forEach which are statements or return undefined.

Every element returned from map() must have a key prop. The key must be stable (not Math.random()) and unique among siblings (not necessarily globally unique). A stable ID from the data source is the correct choice; array index is only acceptable for static, append-only lists.

Combining filter() and map()

For conditional lists (show only in-stock items, show only admin users), chain filter() before map(). filter() returns a new array of only the matching items; map() transforms them. The chain reads naturally: filter what you want, then render each result.

Always handle the empty array case: an empty list renders nothing but gives the user no feedback. Use a ternary or an early return to show an empty state message when no items remain after filtering.

Nested Arrays with flatMap()

For two-dimensional data (categories with items, threads with replies), use flatMap() to flatten and map in one pass instead of nested map() calls. Nested map() returns an array of arrays, which React can render but which makes the JSX harder to read and requires keys at two levels.


Key Code Explained

// Basic: array of strings
function TagList({ tags }: { tags: string[] }) {
  if (tags.length === 0) return <p className="empty">No tags added.</p>;

  return (
    <ul>
      {tags.map((tag) => (
        <li key={tag} className="tag">
          {tag}
        </li>
      ))}
    </ul>
  );
}


// Array of objects with stable IDs
interface Product {
  id: string;
  name: string;
  price: number;
  inStock: boolean;
}

function ProductList({ products }: { products: Product[] }) {
  if (products.length === 0) {
    return <p className="empty">No products found.</p>;
  }

  return (
    <ul className="product-grid">
      {products.map((product) => (
        <li key={product.id} className="product-card">
          <h3>{product.name}</h3>
          <p>${product.price.toFixed(2)}</p>
          {!product.inStock && <span className="badge">Out of stock</span>}
        </li>
      ))}
    </ul>
  );
}


// filter() + map(): render only in-stock products
function InStockProducts({ products }: { products: Product[] }) {
  const available = products.filter((p) => p.inStock);

  if (available.length === 0) {
    return <p className="empty">All products are currently out of stock.</p>;
  }

  return (
    <ul>
      {available.map((product) => (
        <li key={product.id}>{product.name}</li>
      ))}
    </ul>
  );
}


// flatMap(): flatten nested arrays in one pass
interface Category {
  id: string;
  name: string;
  items: { id: string; label: string }[];
}

function FlatItemList({ categories }: { categories: Category[] }) {
  const allItems = categories.flatMap((cat) =>
    cat.items.map((item) => ({ ...item, categoryId: cat.id })),
  );

  return (
    <ul>
      {allItems.map((item) => (
        // key combines category and item IDs to ensure uniqueness
        <li key={`${item.categoryId}-${item.id}`}>{item.label}</li>
      ))}
    </ul>
  );
}


// Common mistake: forgetting return in {} callback
// BAD: returns undefined for every item, renders nothing
{items.map((item) => {
  <li key={item.id}>{item.name}</li>  // missing return
})}

// GOOD: implicit return with ()
{items.map((item) => (
  <li key={item.id}>{item.name}</li>
))}

// GOOD: explicit return with {}
{items.map((item) => {
  return <li key={item.id}>{item.name}</li>;
})}

The flatMap example creates a composite key by joining categoryId and item.id. This is necessary when item IDs are unique only within a category but might repeat across categories. Composite keys keep sibling uniqueness without requiring globally unique IDs.


Tradeoffs

MethodReturnsUse for
map()Transformed arrayRendering every item in an array
filter() + map()Filtered, then transformedRendering a subset that matches a condition
flatMap()Flattened arrayRendering all items across nested arrays
forEach()undefinedSide effects only — never use for rendering

What Interviewers Actually Check

  • Whether you use map() and can explain why (expression vs statement)
  • Whether you use a stable ID as the key, not index
  • Whether you handle the empty array case with a fallback UI
  • Whether you know filter().map() for conditional lists
  • Whether you know forEach() returns undefined and cannot be used for rendering

Follow-Up Questions

  1. How would you virtualize a list of 10,000 items using react-window or react-virtual to avoid rendering all DOM nodes at once?
  2. How does React.Fragment help when map() needs to return multiple sibling elements per item without a wrapper div?
  3. How would you implement infinite scroll pagination that appends more items to the same list on scroll?
  4. How does sorting a list in React differ from sorting in a database query, and what are the performance implications?
  5. How would you memoize list items with React.memo to prevent re-rendering unchanged items when the parent updates?

Common Candidate Mistakes

  • Using forEach() instead of map() and getting nothing rendered (forEach returns undefined)
  • Using array block syntax map((item) => { <li /> }) without a return and getting nothing rendered
  • Using array index as a key on a list that can be filtered or sorted
  • Not handling the empty state, leaving a blank section with no user feedback
  • Using Math.random() as a key thinking it avoids duplicates, not knowing it forces all items to remount every render

Interview Readiness Checklist

Before you leave this question, make sure you can answer:

  • Can you render a list of items using map() with a stable unique key?
  • Can you render a filtered subset using filter().map() with an empty state fallback?
  • Can you render an array of objects and access each field inside the JSX?
  • Can you explain why map() works in JSX but for loops do not?
  • Can you explain why forEach() cannot be used for rendering?

Summary

React renders lists by returning arrays of JSX elements. map() is the primary tool because it is an expression that returns a new array, making it directly usable inside JSX curly braces. For and forEach are statements or return undefined and cannot be used inline in JSX.

Every element from map() needs a key prop that is stable and unique among siblings. A unique ID from the data source is correct; array index causes bugs when the list can reorder or filter. Always handle the empty array case: a list that renders nothing without feedback leaves users confused about whether something went wrong or the list is intentionally empty.

For conditional lists, chain filter() before map() to reduce the array first, then transform the results. For nested arrays (categories with items), use flatMap() to flatten and map in a single pass, avoiding nested map() calls that produce arrays of arrays and require keys at multiple levels.

Related Videos
Watch these videos to learn more about this topic
Frequently Asked Questions

Why use map() instead of a for loop for rendering lists?

map() is an expression that returns a new array of JSX elements, which can be embedded directly in JSX. A for loop is a statement and cannot be used inside JSX curly braces.

Advertisement


Stay Updated

Get the latest frontend challenges, interview questions and tutorials delivered to your inbox.

Advertisement