React map() fails on undefined array props
You're calling .map() on something that's undefined. Usually it's a prop that hasn't arrived yet or a state that starts as undefined.
What's actually happening here
You're rendering a component that calls array.map(...), but array is undefined at the time React tries to render. This almost always means a prop hasn't been passed yet (async data fetch) or it was passed but its initial value is undefined.
I see this most often when people fetch data from an API inside useEffect and try to render the result immediately. The component mounts, data is undefined, and React throws before the fetch completes.
The 30-second fix: Default value in destructuring
This is the one-liner every React dev should know. In the component that receives the array prop, give it a default empty array:
function List({ items = [] }) {
return items.map(item => <li>{item}</li>);
}
If items is undefined, it falls back to []. .map() on an empty array returns an empty array—no crash. This fix works 80% of the time because the data eventually arrives and React re-renders.
But what if items is passed as null? Then this won't help—null isn't undefined. You'd still get a crash because null = [] doesn't apply. Destructuring defaults only kick in for undefined. For that, use the next fix.
The 5-minute fix: Guard clause or optional chaining
When you can't control the parent component's behavior—maybe a third-party library or legacy code—guard the render yourself.
Option A: Guard clause
function List({ items }) {
if (!items) return null;
return items.map(item => <li>{item}</li>);
}
This checks if items is falsy (undefined, null, false, 0, ''). If it is, render nothing. The component stays alive, the parent doesn't break, and when items eventually arrives, React re-renders it.
Option B: Optional chaining + fallback
function List({ items }) {
return (items ?? []).map(item => <li>{item}</li>);
}
The ?? (nullish coalescing) operator only falls through for undefined or null. Unlike ||, it won't replace false or 0 with an empty array—useful when items might legitimately be an empty array or number.
Use optional chaining items?.map(...) only if you want to silently skip the map entirely when items is undefined. But then you get no output, which might hide the bug.
The 15+ minute fix: Trace the data flow and fix the root cause
Band-aids work, but they rot. The real problem is upstream—something in your data flow doesn't deliver the array before the first render.
Step 1: Check your initial state
If you're using useState to hold fetched data, initialize it as an empty array:
const [data, setData] = useState([]);
Not useState() or useState(null). The initial value is what React uses on the first render. An empty array is safe to map over.
Step 2: Verify the prop is actually being passed
Go to the parent component that renders your List. Does it pass items={someData}? If someData is undefined because it comes from another fetch, you've just pushed the problem up. Check that parent's state initialization too.
Step 3: Use useEffect to sync data correctly
If you're fetching data inside the same component, the structure should be:
function App() {
const [items, setItems] = useState([]);
useEffect(() => {
fetch('/api/items')
.then(res => res.json())
.then(data => setItems(data));
}, []);
return <List items={items} />;
}
Notice: items starts as [], so even before the fetch completes, List gets an empty array. No crash.
Step 4: Handle loading and error states
Once the band-aid is gone, add a loading state:
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('/api/items')
.then(res => res.json())
.then(data => {
setItems(data);
setLoading(false);
});
}, []);
if (loading) return <p>Loading...</p>;
return <List items={items} />;
This also prevents a flash of empty list before the data arrives.
Why this error is so common in React
React renders synchronously, but data fetching is asynchronous. The first render happens before the fetch resolves. If your state starts as undefined, React will try to call .map() on it and throw. The error message literally says Cannot read properties of undefined (reading 'map')—it's a runtime type error, not a React bug. Your array is missing.
The fix is always: either ensure the array exists at render time (default value, guard clause) or don't render until the data is ready (loading state). Pick whichever fits your situation. The 30-second fix is fine for a prototype, but for production, do the 15-minute fix. Your future self will thank you when you're debugging at 2 AM.
Was this solution helpful?