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.
// ❌ 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>);
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!
}
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>);
}
// 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
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>);
function List({ items }) {
return items.map(item => <li>{item}</li>); // Error if items not passed!
}
// Usage "” forgot to pass items
<List /> // items is undefined!
// ✅ 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 };
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>
);
}
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.
Explore 500+ free tutorials across 20+ languages and frameworks.