Fix: React TypeError: Cannot read property 'map' of undefined
Quick Answer
How to fix React TypeError Cannot read property map of undefined caused by uninitialized state, async data loading, wrong API response structure, and missing default values.
The Error
Your React app crashes with:
TypeError: Cannot read property 'map' of undefinedOr the modern equivalent:
TypeError: Cannot read properties of undefined (reading 'map')You called .map() on a value that is undefined instead of an array. This typically happens when rendering a list from state or props that has not been initialized or loaded yet.
Why This Happens
.map() is an array method. When you call someVar.map(...), JavaScript first evaluates someVar. If it is undefined (or null), accessing .map on it throws a TypeError.
In React, this commonly occurs because:
- State initialized without a default array.
useState()without an initial value defaults toundefined. - Data not loaded yet. The component renders before the API call completes.
- API response structure changed. The data is nested differently than expected.
- Prop not passed. A parent component did not pass the expected array prop.
- Conditional data. The data exists in some cases but not others.
Fix 1: Initialize State with an Empty Array
The most common fix. Give your state a default empty array:
Broken:
function UserList() {
const [users, setUsers] = useState(); // undefined!
return (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
}Fixed:
function UserList() {
const [users, setUsers] = useState([]); // Empty array — .map() works
return (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
}useState([]) starts with an empty array. .map() on an empty array returns an empty array — no error, no rendered items. When data loads, the state updates and the list renders.
Pro Tip: Always match your state’s initial value to its expected type. If the state should be an array, initialize with
[]. If an object, initialize with{}ornull(and handle thenullcase).
Fix 2: Add a Loading Guard
Check if data exists before rendering:
function UserList() {
const [users, setUsers] = useState(null);
useEffect(() => {
fetch("/api/users")
.then(res => res.json())
.then(setUsers);
}, []);
if (!users) return <p>Loading...</p>;
return (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
}The if (!users) guard prevents rendering the list before data is available. This also provides a better user experience with a loading indicator.
With explicit loading state:
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch("/api/users")
.then(res => res.json())
.then(data => {
setUsers(data);
setLoading(false);
});
}, []);
if (loading) return <p>Loading...</p>;Fix 3: Use Optional Chaining
Use ?. to safely access the array before calling .map():
{users?.map(user => <li key={user.id}>{user.name}</li>)}If users is undefined or null, the entire expression evaluates to undefined — which React ignores (renders nothing). No error.
With a fallback:
{(users ?? []).map(user => <li key={user.id}>{user.name}</li>)}The ?? (nullish coalescing) operator returns [] if users is null or undefined.
Fix 4: Fix API Response Structure
The API might return data in a nested structure:
{
"data": {
"users": [
{"id": 1, "name": "Alice"},
{"id": 2, "name": "Bob"}
]
},
"meta": {
"total": 2
}
}Broken — accessing the wrong level:
const [users, setUsers] = useState([]);
useEffect(() => {
fetch("/api/users")
.then(res => res.json())
.then(data => setUsers(data)); // data is the whole response object!
}, []);
// users.map() fails because users is {data: {users: [...]}, meta: {...}}Fixed — extract the array:
useEffect(() => {
fetch("/api/users")
.then(res => res.json())
.then(response => setUsers(response.data.users)); // Extract the array
}, []);Debug the response shape:
useEffect(() => {
fetch("/api/users")
.then(res => res.json())
.then(data => {
console.log("API response:", data);
console.log("Is array?", Array.isArray(data));
setUsers(data);
});
}, []);For rendering objects directly in JSX, see Fix: Objects are not valid as a React child.
Common Mistake: Assuming the API always returns an array at the top level. Most REST APIs wrap arrays in an object (
{ data: [...] },{ results: [...] },{ items: [...] }). Always check the actual response structure.
Fix 5: Set Default Prop Values
If the array comes from props, provide a default:
Broken:
function ItemList({ items }) {
return (
<ul>
{items.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
);
}
// Parent forgets to pass items:
<ItemList />Fixed — default parameter:
function ItemList({ items = [] }) {
return (
<ul>
{items.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
);
}Fixed — with TypeScript:
interface Props {
items?: Item[];
}
function ItemList({ items = [] }: Props) {
return (
<ul>
{items.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
);
}The items = [] default handles both undefined and missing props.
Fix 6: Fix Context and Redux State
If the array comes from context or Redux:
Broken — context value not initialized:
const DataContext = createContext(); // undefined by default!
function ItemList() {
const { items } = useContext(DataContext); // items is undefined
return items.map(...); // TypeError!
}Fixed — provide a default value:
const DataContext = createContext({ items: [] });Redux — handle initial state:
const initialState = {
users: [], // Always initialize arrays
loading: false,
error: null,
};
function usersReducer(state = initialState, action) {
switch (action.type) {
case "FETCH_SUCCESS":
return { ...state, users: action.payload, loading: false };
default:
return state;
}
}Fix 7: Handle Error States
API calls can fail, leaving state as the initial value:
const [users, setUsers] = useState([]);
const [error, setError] = useState(null);
useEffect(() => {
fetch("/api/users")
.then(res => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
})
.then(data => setUsers(data))
.catch(err => setError(err.message));
}, []);
if (error) return <p>Error: {error}</p>;
return (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);Without error handling, a failed API call leaves users as [] (if initialized correctly) or could set it to an unexpected value.
For useEffect dependency issues that cause infinite loops during data fetching, see Fix: React useEffect infinite loop.
Fix 8: Use Array.isArray() for Type Safety
When you are not sure if a value is an array:
function SafeList({ data }) {
const items = Array.isArray(data) ? data : [];
return (
<ul>
{items.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
);
}Array.isArray() returns true only for actual arrays, not for objects, strings, or other types that might have a .map property.
Still Not Working?
Check for race conditions. If multiple state updates happen quickly, the array might be temporarily set to undefined:
// This can cause a flash of undefined:
setUsers(undefined); // Oops
setUsers(newData); // Fixed — but the first render might crashCheck for data transformation bugs. A .filter() or .find() in the chain might return undefined:
// .find() returns undefined if no match
const activeUsers = users.find(u => u.active);
activeUsers.map(...) // TypeError if no active users found!
// Fix: Use .filter() which always returns an array
const activeUsers = users.filter(u => u.active);
activeUsers.map(...) // Works — empty array if no matchesCheck for stale closures. An async operation might capture an old reference to state. See Fix: React useEffect missing dependency for closure-related issues.
For the general version of this error (not specific to .map), see Fix: TypeError: Cannot read properties of undefined.
If the list renders but keys are wrong, see Fix: Each child should have a unique key.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: React Warning: Failed prop type
How to fix the React 'Warning: Failed prop type' error. Covers wrong prop types, missing required props, children type issues, shape and oneOf PropTypes, migrating to TypeScript, default props, and third-party component mismatches.
Fix: React Cannot update a component while rendering a different component
How to fix React Cannot update a component while rendering a different component caused by setState during render, context updates in render, and Redux dispatch in render.
Fix: Invalid hook call. Hooks can only be called inside of the body of a function component
How to fix the React Invalid hook call error caused by mismatched React versions, duplicate React copies, calling hooks outside components, and class component usage.
Fix: Objects are not valid as a React child (found: [object Object])
How to fix the React error 'Objects are not valid as a React child' caused by rendering plain objects, Date objects, Promises, or API responses directly in JSX.