TypeError: Cannot read property 'map' of undefined

Fix 'Cannot read property map of undefined' in React useEffect

You're trying to map over data that hasn't loaded yet. The fix is to either initialize your state correctly or check for data before mapping.

The 30-Second Fix: Initialize Your State

Most of the time, the error hits because your state starts as undefined. You're trying to call .map() on something that doesn't exist yet. I've seen this happen with a junior dev last week who was fetching a list of products and forgot to set an initial value.

Look at your useState call. If it looks like this:

const [data, setData] = useState();

That's your problem. useState() with no argument gives you undefined. Change it to an empty array:

const [data, setData] = useState([]);

That's it. Test it. Your data.map(...) now runs on an empty array until the API returns real data. No crash.

If the data you're mapping over isn't the state variable itself but a nested property — like data.items.map(...) — you need to handle that too. Check if data itself exists before accessing .items. More on that in the next section.

The 5-Minute Fix: Guard Your Map Call

Sometimes the data structure isn't a simple array. Maybe your API returns an object like { users: [...], meta: {...} }. In that case, initializing to an empty array won't help because you need to map over data.users, not data.

The fix is to guard your map call with a conditional check. Use optional chaining or a ternary operator.

Optional chaining (modern, clean):

{data?.users?.map(user => <li key={user.id}>{user.name}</li>)}

Ternary operator (works everywhere):

{data && data.users ? data.users.map(...) : null}

I prefer optional chaining in codebases targeting modern browsers. Had a client running an old Electron app that didn't support it, so we used the ternary. Both work.

Also, check if your API might return the data in a different shape than expected. I've seen APIs silently change a field name from items to results and break everything. Log the response first:

useEffect(() => {
fetch(url)
.then(res => res.json())
.then(data => {
console.log('API response:', data);
setData(data);
});
}, []);

Look at the console. Is it data.items or data.results? Adjust your mapping accordingly.

The 15+ Minute Fix: Loading States and Error Handling

If the simple fixes don't cut it, you're dealing with a more complex issue. Maybe your API call fails silently, or the component renders before the effect runs. The advanced fix is to build a robust loading flow.

Add a loading state:

const [loading, setLoading] = useState(true);

In your useEffect, set loading to true before fetching, then false after. Return a spinner or null while loading:

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

This prevents the component from rendering until data is ready. No more map on undefined.

Catch API errors gracefully:

useEffect(() => {
fetch(url)
.then(res => {
if (!res.ok) throw new Error('Network response was not ok');
return res.json();
})
.then(data => {
setData(data);
setLoading(false);
})
.catch(err => {
console.error('Fetch error:', err);
setLoading(false);
// Optionally set an error state
});
}, []);

Had a client last month whose API was returning a 500 error from the server. Without error handling, the component just showed blank and the map error popped up because data was never set. Adding a catch block and a loading state fixed it completely.

Consider using a library like React Query or SWR:

If you're doing this often, these libraries handle caching, loading states, and error handling out of the box. They're overkill for one fetch but lifesavers for complex apps.

One more edge case: If your useEffect depends on a prop or state that changes, you might trigger a re-fetch and cause a race condition. Use an AbortController to cancel old requests:

useEffect(() => {
const controller = new AbortController();
const signal = controller.signal;

fetch(url, { signal })
.then(res => res.json())
.then(data => {
if (!signal.aborted) setData(data);
})
.catch(err => {
if (err.name !== 'AbortError') console.error(err);
});

return () => controller.abort();
}, [url]);

This won't fix the map error directly, but it prevents stale data from causing confusion.

Bottom line: the map error is almost always a timing issue. Initialize your state, guard your renders, and handle failures. Start with the 30-second fix, and you'll be done in most cases.

Related Errors in Programming & Dev Tools
Module not found: Error: Can't resolve 'fs' Webpack 'fs' module not found error in browser environment SSLError(SSLCertVerificationError) Pip install SSLError: connection broken fix (proxy/SSL) ModuleNotFoundError Fix Python ModuleNotFoundError: No module named X 0XC0000354 STATUS_DEBUGGER_INACTIVE (0XC0000354) – Fix & Why It Happens

Was this solution helpful?

EP
Erropedia Team
Tech Support Editors
The Erropedia editorial team researches and documents real-world tech errors from across Windows, Linux, macOS, networking, databases, cloud platforms, and more. Every solution is reviewed for accuracy and updated as software and systems evolve.