Tutorials Logic, IN info@tutorialslogic.com

Cannot read map of undefined in React Fix: Causes, Fixes, Examples & Interview Tips

Cannot read map of undefined in React Fix

This error is a data-shape problem. React renders before async data arrives, so a value that will eventually be an array may be undefined during the first render.

A detailed fix includes both initialization and UI states: initialize list state as [], show loading while the request runs, show an error when the request fails, and confirm the API response is actually an array before calling map.

Cannot read map of undefined in React needs more than a syntax memory trick. The important idea is to understand initial state, async data loading, array guards, optional chaining, loading UI, and API response shape checks in the exact situation where the page topic appears, then prove the behavior with a small working example and one edge case.

What is This Error?

The error "Cannot read properties of undefined (reading 'map')" is extremely common in React. It occurs when you try to call .map() on a variable that is undefined or null "" usually because async data hasn't loaded yet, or an API returned an unexpected shape.

Common Causes

  • State initialized as undefined instead of an empty array
  • API data not loaded yet when component first renders
  • API response has a different shape than expected
  • Prop not passed to component (undefined by default)
  • Accessing a nested property that doesn't exist

Quick Fix (TL;DR)

Quick Solution

Quick Solution
// ❌ Problem
const [users, setUsers] = useState(); // undefined!
return users.map(u => <p>{u.name}</p>); // Error!

// ✅ Solution 1: Initialize with empty array
const [users, setUsers] = useState([]);

// ✅ Solution 2: Optional chaining
return users?.map(u => <p>{u.name}</p>);

// ✅ Solution 3: Fallback
return (users || []).map(u => <p>{u.name}</p>);

Common Scenarios & Solutions

Problem

Problem
function ProductList() {
  const [products, setProducts] = useState(); // ❌ undefined!

  useEffect(() => {
    fetch('/api/products')
      .then(r => r.json())
      .then(setProducts);
  }, []);

  return products.map(p => <div key={p.id}>{p.name}</div>); // Error on first render!
}

Solution

Solution
function ProductList() {
  const [products, setProducts] = useState([]); // ✅ Empty array default
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch('/api/products')
      .then(r => r.json())
      .then(data => {
        setProducts(data);
        setLoading(false);
      });
  }, []);

  if (loading) return <p>Loading...</p>;
  return products.map(p => <div key={p.id}>{p.name}</div>);
}

Problem

Problem
// API returns: { data: { users: [...] } }
useEffect(() => {
  fetch('/api/users')
    .then(r => r.json())
    .then(setUsers); // ❌ Sets users to { data: { users: [...] } }
}, []);

return users.map(u => <p>{u.name}</p>); // Error! users is an object

Solution

Solution
useEffect(() => {
  fetch('/api/users')
    .then(r => r.json())
    .then(response => {
      setUsers(response.data.users); // ✅ Extract the array
    });
}, []);

// Or with optional chaining as safety net
return (users ?? []).map(u => <p>{u.name}</p>);

Problem

Problem
function List({ items }) {
  return items.map(item => <li>{item}</li>); // Error if items not passed!
}

// Usage "" forgot to pass items
<List /> // items is undefined!

Solution

Solution
// ✅ Default prop value
function List({ items = [] }) {
  return items.map(item => <li key={item}>{item}</li>);
}

// ✅ Or with PropTypes
import PropTypes from 'prop-types';
List.defaultProps = { items: [] };
List.propTypes = { items: PropTypes.array };

Solution

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

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

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;
  if (!data || !Array.isArray(data)) return <p>No data</p>;

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

Best Practices to Avoid This Error

  • Always initialize array state with [] - Never leave it as undefined
  • Use loading states - Show a spinner while data is being fetched
  • Validate API response shape - Log the response to verify its structure
  • Use default props - Provide fallback values for array props
  • Use optional chaining - data?.map() returns undefined instead of throwing
  • Check Array.isArray() - Verify data is actually an array before mapping
  • Handle errors gracefully - Show error messages when fetch fails

Related Errors

First Render and Async Data

React does not wait for useEffect before rendering the component. The first render uses the initial state. If the initial state is undefined and JSX calls users.map(...), JavaScript throws before React can show the intended list.

The simplest fix is to initialize the state with the same shape you plan to render. If the UI renders a list, start with an empty array. If the UI renders an object, start with null and guard the object before reading properties.

  • Use useState([]) for lists.
  • Use Array.isArray when API shape is uncertain.
  • Render loading and error states explicitly.
  • Do not call map on undefined, null, or an object.

API Response Shape Notes

Many APIs return an object that contains the array, such as { users: [...] } or { data: [...] }. If you store the whole object and then call response.map, the code fails because the object itself is not an array.

Inspect the response once, choose the exact array field, and store that field in state. This makes rendering simpler and prevents repeated optional chaining throughout the JSX.

  • Check whether the array is response, response.data, or response.users.
  • Store normalized data in state.
  • Keep fallback arrays for missing optional sections.
  • Avoid hiding bad API shapes silently in production code.

Fixing map errors by controlling the first render

Cannot read map of undefined usually appears when a React component renders before async data has arrived. The first render happens with the initial state, so if users is undefined and the JSX calls users.map(), JavaScript throws before React can show the list. The fix begins with choosing a safe initial value.

For list data, initialize state as an empty array when the UI expects an array. If the API shape is uncertain, verify it before storing it. Loading and empty states also make the component clearer: loading explains that data is still coming, empty explains that the request succeeded but there are no items.

  • Initialize list state with [] instead of undefined.
  • Check API response shape before calling setState.
  • Render loading and empty states separately.
  • Use Array.isArray when data may not be an array.

Wrong: users Starts as undefined

Wrong: users Starts as undefined
function UserList() {
  const [users, setUsers] = useState();

  return users.map(user => <p key={user.id}>{user.name}</p>);
}

Correct: Initialize and Render States

Correct: Initialize and Render States
function UserList() {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch("/api/users")
      .then(res => res.json())
      .then(data => setUsers(Array.isArray(data) ? data : data.users ?? []))
      .finally(() => setLoading(false));
  }, []);

  if (loading) return <p>Loading...</p>;

  return users.map(user => <p key={user.id}>{user.name}</p>);
}

Safe list rendering after async fetch

Safe list rendering after async fetch
function UsersList() {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch('/api/users')
      .then(res => res.json())
      .then(data => setUsers(Array.isArray(data) ? data : []))
      .finally(() => setLoading(false));
  }, []);

  if (loading) return <p>Loading...</p>;
  return users.map(user => <p key={user.id}>{user.name}</p>);
}
Key Takeaways
  • Initialize list state with an empty array.
  • Check whether API data is actually an array.
  • Add loading and error UI states.
  • Use stable keys when mapping.
  • Avoid mapping before data shape is known.
  • I can explain what value users has during the first render, loading render, and loaded render.
Common Mistakes to Avoid
WRONG Starting list state as undefined.
RIGHT Start with [] when JSX maps the value.
Initial state should match render shape.
WRONG Mapping the whole API response object.
RIGHT Map the exact array field.
Inspect response shape before rendering.
WRONG Using optional chaining as the only fix.
RIGHT Also handle loading, errors, and wrong data shape.
Optional chaining avoids a crash but may hide missing data.
WRONG Adding optional chaining everywhere without checking why the data is undefined.
RIGHT Set a correct initial state and validate the API response before rendering the list.
Explain the cause in one sentence before changing the code.

Practice Tasks

  • Build a list component with loading, success, empty, and error states.
  • Change the API shape from array to object and update the mapping logic.
  • Write a guard using Array.isArray before rendering.
  • Explain why useEffect data is not available during the first render.
  • Build a posts list with loading, empty, success, and invalid-response states.

Frequently Asked Questions

Because data fetched in useEffect isn't available on the first render. The component renders once with the initial state (undefined if not set), then useEffect runs and fetches data, triggering a second render with the actual data.

Initialize your state as an empty array: useState([]). Add a loading state to show a spinner while data loads. Use optional chaining: data?.map() as a safety net.

Both cause the same error. undefined is the default when no value is assigned. null is explicitly set to "no value". Both need to be handled before calling .map().

Use a try/catch block or .catch() in your fetch chain. Store the error in state and show an error message. Always check if data exists and is an array before mapping.

Yes! data?.map(item => ...) returns undefined if data is null/undefined instead of throwing an error. You can also use (data ?? []).map() to fall back to an empty array.

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.