Reputation: 8955
I have the following React component.
import React, { Component } from 'react';
class VesselDropdown extends Component {
constructor(props) {
super(props)
this.state = {
}
}
componentDidMount() {
fetch('http://localhost:3001/get/vessels')
.then(res => res.json())
.then((data) => {
this.setState({
vessels: data,
test: 'xyz'
})
})
.catch(console.log)
}
render() {
console.log(this.state);
return (
<div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
<h1>Move the mouse around!</h1>
<p>The current mouse position is ({this.state.test})</p>
{
this.state.vessels.map(d => {
console.log(d);
return <div>test</div>
})
}
</div>
);
}
}
export default VesselDropdown;
I am trying to render some data that is stored in the state. But I get the following errors:
Cannot read property 'map' of undefined
If I remove the following code, I get no errors, and it displays the 'xyz' in the browser.
{
this.state.vessels.map(d => {
console.log(d);
return <div>test</div>
})
}
Question:
Do you know what I am doing incorrectly? Why cannot I not get the vessels
data from the state?
Thanks
More info:
GET http://localhost:3001/get/vessels
returns:
[{"vesselimo":9337626,"vesselname":"NYK CONSTELLATION"}]
Upvotes: 0
Views: 402
Reputation: 7110
Set initial state of vessels in your constructor.
For example
this.state={
vessels:[]
}
This helps the map method to execute without throwing an undefined error
Upvotes: 2
Reputation: 21
Since componentDidMount runs a synchronous function, means the component will be rendered even before the data is available, so try adding a condition to the code block like this.
this.state.vessels && this.state.vessels.map(d => {
console.log(d);
return <div > test < /div>
})
}
Don't forget to initialise vessels as an empty array i.e
this.state={
vessels:[]
}
This will ensure that the block would be rendered only when you have some data in the state.
Upvotes: 1
Reputation: 15166
The reason behind that is fetch
is asynchronously returning the response for your array, meanwhile render
tries to call map()
on your non existing array. Which is happening faster than the response arrives. That's why you got that error message on the console.
You need to define maybe an empty array for vessels
state in the constructor. Or checking before calling map()
if the value is undefined
or null
by using &&
operator.
Adding default empty array solution - map()
can be called on an empty array:
constructor(props) {
super(props);
this.state = {
vessels: []
};
}
Or in the render
checking with &&
operator:
{
this.state.vessels && this.state.vessels.map(d => {
console.log(d);
return <div>test</div>
})
}
Both will do the job for you.
+1 suggestion:
Once you do map()
you need to add for each returned element in render
a key
for the wrapper element. So my suggestion would be to add as the following:
this.state.vessels && this.state.vessels.map((d, index) => {
return <div key={index}>test</div>
})
I hope that helps!
Upvotes: 2