In your React component:
const [users, setUsers] = useState([]);
→ users
starts as an empty array, which is fine.
Your fetch request:
fetch("http://localhost:5000/api/users")
.then((res) => res.json())
.then((data) => setUsers(data))
→ If Express returns an array of users, this works.
The error:
TypeError: Cannot read properties of undefined (reading 'map')
→ This happens only if users
is undefined
(not an array).
That means setUsers(data)
is being called with undefined
instead of an array.
Check what your backend actually returns:
useEffect(() => {
fetch("http://localhost:5000/api/users")
.then((res) => res.json())
.then((data) => {
console.log("API response:", data); // debug
setUsers(data || []); // fallback to empty array
})
.catch((err) => console.error(err));
}, []);
Your API response is wrapped
Some MySQL drivers return [rows, fields]
.
If so, results
in your backend is actually an array inside another array.
Fix backend route:
db.query("SELECT * FROM users", (err, results) => {
if (err) return res.status(500).json({ error: err.message });
res.json(results); // ensure results is the array of rows only
});
CORS issue (if deployed or different host)
On localhost, it often works, but in production you’ll need CORS:
import cors from "cors";
app.use(cors());
Frontend safety check
Never call .map()
on something you’re not 100% sure is an array:
<ul>
{Array.isArray(users) && users.map((u) => (
<li key={u.id}>{u.name}</li>
))}
</ul>
export default function Home() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch("http://localhost:5000/api/users")
.then((res) => res.json())
.then((data) => {
console.log("API response:", data);
setUsers(Array.isArray(data) ? data : []);
})
.catch((err) => console.error(err));
}, []);
return (
<div>
<h1>User List</h1>
<ul>
{users.map((u) => (
<li key={u.id}>{u.name}</li>
))}
</ul>
</div>
);
}
Most likely your Express API is returning [rows, fields]
and you only need the rows
.