Cannot read property 'map' of null

Viewed 1142

I've got a React component that makes a call to a backend API which returns an array of objects. Essentially, I've got a useFetch.js file that fetches data and is then displayed in a Products.js file

My main issue is that when I simply log the data that is returned, no matter how many times I refresh my browser, the correct data is always logged. However, as soon as I include a map to render the data, it displays only for the first time, and then I get an error

Cannot read property 'map' of null

The breakdown in the simple scenario when I just log the data:

Products.js

import React from "react";

import useFetch from "./useFetch";
import DisplayTable from "./DisplayTable"

export default function Products(props) {
    const [data, loading, error] = useFetch("http://localhost:8080/products");
    console.log("data", data)
    console.log("loading", loading)
    console.log("error", error)

    return (
        <div>
            
        </div>
    )
}

useFetch.js

import { useState, useEffect } from "react";

export default function useFetch(url) {
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState(false);
    const [data, setData] = useState(null);

    async function asyncFetchAPI() {
        setLoading(true)
        fetch(url, {method: "GET"})
            .then(response => response.json())
            .then(data => setData(data))
            .then(loading => setLoading(false))
            .catch((error) => {
                 console.log('error: ' + error)
                 setError(true)
            })
    }

    useEffect(() => {
        asyncFetchAPI();
    }, []);

  return [data, loading, error];
}

The above works fine, and I can see the data in the console perfectly well. However, when I modify Products.js to include the map and display as follows

const displayTable = data.map(item => <DisplayTable key={item.id} item={item} />)

The new result is now:

import React from "react";

import useFetch from "./useFetch";
import DisplayTable from "./DisplayTable"

export default function Products(props) {
    const [data, loading, error] = useFetch("http://localhost:8080/products");
    console.log("data", data)
    console.log("loading", loading)
    console.log("error", error)

    const displayTable = data.map(item => <DisplayTable key={item.id} item={item} />)

    return (
        <div>

        </div>
    )
}

At that point, I get

Cannot read property 'map' of null

For what it's worth, my DisplayTable.js function looks like:

import React from "react"

function DisplayTable(props) {
    console.log(props)
    return (
        <h1>{props.item.categoryId}</h1>
    )
}

export default DisplayTable
2 Answers

You can fix it by initializing your data state with empty array in your useFetch.js file

const [data, setData] = useState([]);

or in the other file i.e.

const [data = [], loading, error] = useFetch("http://localhost:8080/products");

The problem is you are requesting data in an asynchronous manner right, so the first time, it is returned as null, then you try to map over null. e.g. Here your data is null initially

const [data, setData] = useState(null);

console.log sometimes may show you the current state of variable, so don't get deceived by that.

So before mapping you can put a condition something like:

data && data.map....

or use empty array as initial value

Related