The error Cannot read property 'map' of undefined' is thrown when the map function in the CommentList component is executed. Uncaught TypeError: Cannot read property 'value' of undefined is strictly a JavaScript error. (Note that value can be anything, but for this question value is 'map') Does this answer your question? Line 0: Parsing error: Cannot read property 'map' of undefined – Henke Mar 23 at 14:00
// NOTE - This solution works when your working with REACT-QUERY
const fetchPlanets = async (page) => {
// const [_key, page] = queryKey;
const response = await fetch(`https://swapi.dev/api/planets/?page=${page}`);
if (!response.ok) {
throw new Error("Network response was not ok");
}
return response.json();
};
const Planents = () => {
const [page, setPage] = useState(2);
//this point did the magic, and enable the [page-state]
//to be seen at the fetch function
const { data, status } = useQuery(["planets", page], () =>
fetchPlanets(page)
);
console.log(data);
return (
<div>
<h2>Planets</h2>
{status === "pending" && <div>Loading Data</div>}
{status === "error" && <div>Error fetching data</div>}
{status === "success" && (
<div>
{data.results.map((planet) => {
return <SinglePlanet key={planet.name} planet={planet} />;
})}
</div>
)}
</div>
);
};
First of all, set more safe initial data:
getInitialState: function() {
return {
data: {
comments: []
}
};
},
It should work if you follow above two instructions like Demo.
Updated: you can just wrap the .map block with conditional statement.
if (this.props.data) {
var commentNodes = this.props.data.map(function (comment){
return (
<div>
<h1>{comment.author}</h1>
</div>
);
});
}
to
data = {
this.state.data
}
in the render function of CommentBox. I did the same mistake when I was following the tutorial. Thus the whole render function should look like
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.state.data} />
<CommentForm />
</div>
);
}
The variable you are trying to map over is undefined. It will probably eventually be an array, but due to the asynchronous nature of React, you are experiencing at least one render when the variable is undefined. And now we have a pretty safe way of handling our async operation without getting the dreaded “cannot read property ‘map’ of undefined” error! We should probably handle the situation in which our fetch fails. Additionally, we can show the user an error message if our data variable is not an array. This latter point is important in making sure that we never try to access the map property on a non-array since it simply won’t work.
Cannot read property 'map' of undefined
function MyComponent() {
const [data, setData] = useState();
useEffect(() => {
fetch('/api/data')
.then((res) => res.json())
.then((data) => {
setData(data);
})
.catch((err) => {
console.log(err);
});
}, []);
return (
<ul>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
function MyComponent() {
// Empty array in useState!
const [data, setData] = useState([]);
useEffect(() => {
fetch('/api/data')
.then((res) => res.json())
.then((data) => {
setData(data);
})
.catch((err) => {
console.log(err);
});
}, []);
return (
<ul>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
function MyComponent() {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState();
useEffect(() => {
setLoading(true);
fetch('/api/data')
.then((res) => res.json())
.then((data) => {
setData(data);
})
.catch((err) => {
setError(err);
})
.finally(() => {
setLoading(false);
});
}, []);
if (loading) {
return <p>Data is loading...</p>;
}
if (error || !Array.isArray(data)) {
return <p>There was an error loading your data!</p>;
}
return (
<ul>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
When we get such an error, we are probably getting the value in an asynchronous way. We should provide an initial value for our variable or conditionally render it or both. If our condition become too complex, it might be a good time to extract the logic to a component. One possible solution is to give your variable a default initial value, with useState it would look like that: But instead we can create a variable outside our tree and populate it conditionally:
// Just a data fetching function
const fetchURL = "https://jsonplaceholder.typicode.com/todos/";
const getItems = () => fetch(fetchURL).then(res => res.json());
function App() {
const [items, setItems] = useState();
useEffect(() => {
getItems().then(data => setItems(data));
}, []);
return (
<div>
{items.map(item => (
<div key={item.id}>{item.title}</div>
))}
</div>
);
}
const [items, setItems] = useState();
useEffect(() => {
getItems().then(data => setItems(data));
}, []);
[ [], fn ]
// ⚠️ wont work!!
export default function App() {
// ....
return (
<div>
{
if(items){ items.map(item => ( <div key={item.id}>{item.title}</div> )) } }
</div>
);
}
The "Uncaught TypeError: Cannot read properties of undefined (reading 'map')" error occurs in JavaScript, whenever you try to use the array map method on a variable that is undefined. This can usually happen in React, whenever you need to loop through an array of elements and display them. However, the array on which you are executing the map is undefined. This means that JavaScript sees the following code, and throws the above error: In order to fix the error, you need to make sure that the array is not undefined. In order to do this, the simplest way is to use optional chaining.
{posts.map(post => <Card details={post} />)}
// Trying to run map on undefined
{undefined.map(post => <Card details={post} />)}
// Or simply try to run in your console
undefined.map()
{posts?.map(post => <Card details={post} />)}
This error usually means you’re trying to use .map on an array, but that array isn’t defined yet. That’s often because the array is a piece of undefined state or an undefined prop. Make sure to initialize the state properly. That means if it will eventually be an array, use useState([]) instead of something like useState() or useState(null). It would be way more useful if the error could say “Cannot read property `map` of items”. Sadly it doesn’t say that. It tells you the value of that variable instead.
6 | return ( 7 | <div className="App"> 8 | <h1>List of Items</h1>> 9 | {items.map((item) => ( | ^ 10 | <div key={item.id}> 11 | {item.name} 12 | </div>
TypeError: Cannot read property 'map' of undefined
at App (App.js:9)
at renderWithHooks (react-dom.development.js:10021)
at mountIndeterminateComponent (react-dom.development.js:12143)
at beginWork (react-dom.development.js:12942)
at HTMLUnknownElement.callCallback (react-dom.development.js:2746)
at Object.invokeGuardedCallbackDev (react-dom.development.js:2770)
at invokeGuardedCallback (react-dom.development.js:2804)
at beginWork$1 (react-dom.development.js:16114)
at performUnitOfWork (react-dom.development.js:15339)
at workLoopSync (react-dom.development.js:15293)
at renderRootSync (react-dom.development.js:15268)
at performSyncWorkOnRoot (react-dom.development.js:15008)
at scheduleUpdateOnFiber (react-dom.development.js:14770)
at updateContainer (react-dom.development.js:17211)
at eval (react-dom.development.js:17610)
at unbatchedUpdates (react-dom.development.js:15104)
at legacyRenderSubtreeIntoContainer (react-dom.development.js:17609)
at Object.render (react-dom.development.js:17672)
at evaluate (index.js:7)
at z (eval.js:42)
at G.evaluate (transpiled-module.js:692)
at be.evaluateTranspiledModule (manager.js:286)
at be.evaluateModule (manager.js:257)
at compile.ts:717
at l (runtime.js:45)
at Generator._invoke (runtime.js:274)
at Generator.forEach.e.<computed> [as next] (runtime.js:97)
at t (asyncToGenerator.js:3)
at i (asyncToGenerator.js:25)
at App(App.js: 9)
import "./styles.css";
export default function App() {
let items;
return (
<div className="App">
<h1>List of Items</h1>
{items.map(item => (
<div key={item.id}>
{item.name}
</div>
))}
</div>
);
}
{
items.map(item => (
As a result, the TypeError Cannot read property 'map' of undefined is very common and one of the first errors that developers will be confronted with. It occurs when the variable being executed is of a different type than expected. Recognizing the error and the root cause will save you valuable time in the long run. In this section, you’ll discover what causes the TypeError Cannot read property 'map' of undefined and how to prevent it. The TypeError Cannot read property 'map' of undefined occurs in the following situations:
Unfortunately, in the real world, APIs can be inconsistent. The response might be in a different format than you expected, and if you don’t add some checks, your code could run into some issues.
Here is an example using Nationalize.io, an API predicting the nationality of a name passed as a parameter:
// Working fine
const name = 'marie'
fetch(`https://api.nationalize.io/?name=${name}`)
.then(res => res.json())
.then(data => {
// Data returned : { country: [{country_id: 'RE', probability: 0.0755}, ...], name: "marie"}
data.country.map((country_details) => console.log(country_details))
});
// Throwing an error
const emptyName = ''
fetch(`https://api.nationalize.io/?name=${emptyName}`)
.then(res => res.json())
.then(data => {
// Data returned: { error: "Missing 'name' parameter"}
const {
country
} = data
country.map((country_details) => console.log(country_details))
// Throws TypeError cannot read property ‘map’ of undefined
});
Developers are humans and, therefore, make typos. Similar to the previous example, if you access a property that doesn’t exist on an object, the value will be undefined.
Calling the map
method will throw the TypeError Cannot read property 'map' of undefined
:
const library = {
name: "Public library",
books: [“JavaScript complete reference guide”]
}
// ‘bookss’ is not a property of library, so this will throw an error
library.bookss.map(book => console.log(book))
It’s easy to make a call and forget to take into consideration whether it’s an asynchronous one. When a value is populated asynchronously, accessing it too early will result in an error, as the value might still be undefined:
const fetchCountries = (name) => {
fetch(`https://api.nationalize.io/?name=${name}`)
.then(res => res.json())
.then(data => {
console.log(data)
return data
});
}
const name = 'marie'
const countriesData = fetchCountries(name)
console.log(countriesData)
The third solution is optional chaining. This simple operator will short-circuit and return undefined if you call a function on a property that doesn’t exist:
const library = {
name: "Public library"
}
// books is not a property of library, but with the ? operator, this only returns undefined
library.books?.map(book => console.log(book))
Finally, you can wrap your call in a try-catch block. You can read more about try-catch here. In the case of API calls that may fail and return error messages, like the first example, you can also use a catch()
after your then ()
function to handle errors.
For this situation, libraries such as Axios are preferred over fetch, as the latter will only throw an error on network issues and not on API errors (such as a 500). Axios, on the other hand, comes with error handling:
const param = ''
axios.get(`https://api.nationalize.io/?name=${param}`)
.then(data => {
// This will not get executed
data.country.map((country_details: any) => console.log(country_details))
})
.catch(error => console.log(error));