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.
Prevent React map-of-undefined failures by initializing list state consistently, validating API shapes, and rendering loading or error states before iteration.
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.
// Wrong Problem
const [users, setUsers] = useState(); // undefined!
return users.map(u => <p>{u.name}</p>); // Error!
// Correct Solution 1: Initialize with empty array
const [users, setUsers] = useState([]);
// Correct Solution 2: Optional chaining
return users?.map(u => <p>{u.name}</p>);
// Correct Solution 3: Fallback
return (users || []).map(u => <p>{u.name}</p>);
function ProductList() {
const [products, setProducts] = useState(); // Wrong 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!
}
function ProductList() {
const [products, setProducts] = useState([]); // Correct 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>);
}
// API returns: { data: { users: [...] } }
useEffect(() => {
fetch('/api/users')
.then(r => r.json())
.then(setUsers); // Wrong Sets users to { data: { users: [...] } }
}, []);
return users.map(u => <p>{u.name}</p>); // Error! users is an object
useEffect(() => {
fetch('/api/users')
.then(r => r.json())
.then(response => {
setUsers(response.data.users); // Correct Extract the array
});
}, []);
// Or with optional chaining as safety net
return (users ?? []).map(u => <p>{u.name}</p>);
function List({ items }) {
return items.map(item => <li>{item}</li>); // Error if items not passed!
}
// Usage "" forgot to pass items
<List /> // items is undefined!
// Correct Default prop value
function List({ items = [] }) {
return items.map(item => <li key={item}>{item}</li>);
}
// Correct Or with PropTypes
import PropTypes from 'prop-types';
List.defaultProps = { items: [] };
List.propTypes = { items: PropTypes.array };
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>
);
}
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.
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.
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.
function UserList() {
const [users, setUsers] = useState();
return users.map(user => <p key={user.id}>{user.name}</p>);
}
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>);
}
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>);
}
Try this next
0 of 2 completed
A fetch started in useEffect runs after the first render, so the first render uses whatever initial value you gave the state.
Start by checking the value you are mapping.
For .map(), both are non-arrays, so both fail. undefined usually means no value was assigned yet, while null usually means the code intentionally recorded "no value." That distinction matters for UI design. undefined may belong to a loading state, while null may mean the server returned nothing or the user cleared a selection. Do not treat every non-array as the same.
Explore 500+ free tutorials across 20+ languages and frameworks.