3

I am trying to fetch data from MongoDB (using node.js and express) and show them as markers on a Leaflet map, using react leaflet. However, I always get an error: Unhandled rejection (TypeError): this.state.images.map is not a function. I am not sure why I get this error, since my data looks fine in the console log.

My server:

imageRouter.get((req, res, next) => {
    ImageEntry.find({})
        .then(images => {
            res.status(200).json({
                images,
            });
        })
        .catch(err => res.status(500).json(err));
});

My client (API.js):

    export async function getImages() {
    const response = await fetch(API_URL);
    return response.json();  
}

My client (App.js):

        state = {
         location: {
          lat: 63.430515,
          lng: 10.395053,
        },
        zoom: 5,
        images: [],
      }

componentDidMount() {
    getImages()
      .then(images => {
        this.setState({
          images
        });
      });
  }

render(){
    const position = [this.state.location.lat, this.state.location.lng];

    console.log(this.state.images);

    return (
      <div className="app">
        <Map className="map" center={position} zoom={this.state.zoom}>
          <TileLayer
            attribution='&copy; <a 
            href="http://osm.org/copyright">OpenStreetMap</a> 
            contributors'
            url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
          />
          {
            this.state.images.map(image => (
              <Marker
                key={image._id}
                position={[image.latitude, image.longitude]}
                icon={imageIcon}>
                <Popup>
                  <p><em>{image.prosjekt}</em> {image.prosjektOmrade}</p>
                </Popup>
              </Marker>
            ))}
        </Map>
    );
  }

I have tried to print images inside the render to see if I get the right result. When I refresh the page, the array is empty but after som ms the array have some objects inside. It is showing the following:

[]
 length: 0
 __proto__: Array(0)

After som ms

{images: Array(4)}
    images: Array(4)
     0: {_id: "6026b6c272d2e50d47533055", prosjekt: "E6KAA", prosjektOmrade: "Holvegen", parsell: 1200, kategori: "VVS", …}
     1: {_id: "602804da7be224141e19b38d", prosjekt: "E6KAA", prosjektOmrade: "Holvegen", parsell: 1200, kategori: "VVS", …}
     2: {_id: "602ab78bbde3a7233bf9954e", prosjekt: "E6KAA", prosjektOmrade: "Bro", parsell: 233, kategori: "Bro", …}
     3: {_id: "602d31a9311aec0f1bef820f", prosjekt: "E6KAA", prosjektOmrade: "rundkjøring", parsell: 400, kategori: "Vei", …}
     length: 4
    __proto__: Array(0)
    __proto__: Object

I can't figure out why I get the error, really hope anyone can help me. Really appreciated, thanks!

kboul
  • 13,836
  • 5
  • 42
  • 53
Helene
  • 33
  • 3
  • Probably `this.state.images` is empty for a few seconds before data is fetched. try using an expression `this.state.images.length > 0 && this.state.images.map...` to ensure data array is populated – kboul Feb 19 '21 at 11:28
  • It helps against the error message, but no markers are made on the map... Do you know of a way to make the function wait to run until the values ​​have arrived in the array? @kboul – Helene Feb 19 '21 at 12:19
  • Are you sure the response is an array of objects and not an array of array of objects for instance or sth else? – kboul Feb 19 '21 at 12:32
  • That is a good question. I thought it was just an array, but when you mention it maybe it is an array of array of objects. When I see it in the console I have to "open" the **{images: Array(4)}** and then "open" **images: Array(4)**, to be able to see all the objects. Do you know how to get to det innermost array? – Helene Feb 19 '21 at 13:03

1 Answers1

1
componentDidMount() {
    getImages()
      .then(images => {
        this.setState({
          images: images.images
        });
      });
  }

or by destructuring

 componentDidMount() {
        getImages()
          .then(({images}) => {
            this.setState({ images });
          });
      }

From the comments:

  1. this.state.images is empty for a few seconds before data is fetched. try using an expression this.state.images.length > 0 && this.state.images.map... to ensure data array is populated
  2. If the model of data returned is an array of arrays of objects just access the data by making images.images but it is difficult to say exactly without knowing the exact form of the data returned.
kboul
  • 13,836
  • 5
  • 42
  • 53