Home > Net >  useState from API returning an empty array
useState from API returning an empty array

Time:11-05

I'm having some issues populating data from an API. When I console.log the state "dataFromApi", it's working just fine. Meaning, I'm getting an arr of multiple objects.

However, I then plugged in the API data from the state into the "columnsFromBackend", "items" section. When I then console.log the "columns" state at the bottom of the page which is just all the data from "columnsFromBackend", it returns me all the hardCodedData but not the one from the API.

Meaning, I'm just receiving an empty array. This is the output from the console.log(columns). Any suggestions on what might be happening here?

enter image description here

    const [dataFromApi, setDataFromApi] = useState([]);

    useEffect(() => {
        getLeadsClApproved().then((resp) => {
            setDataFromApi(resp.data);
        });
    }, []);

    const hardCodedData = [
        {
            id: uuid(),
            business_name: "Canva",
            first_name: "Melanie",
            last_name: "Perkins",
            created_at: "15th of Nov., 2022",
        },
        {
            id: uuid(),
            business_name: "Microsoft",
            first_name: "Bill",
            last_name: "Gates",
            created_at: "15th of Nov., 2022",
        },
    ];

    const columnsFromBackend = {
        [uuid()]: {
            name: "In Progress",
            items: hardCodedData,
        },
        [uuid()]: {
            name: "CL Approved",
            items: dataFromApi,
        },
        [uuid()]: {
            name: "CL Declined",
            items: [],
        },
        [uuid()]: {
            name: "Awaiting Response",
            items: [],
        },
        [uuid()]: {
            name: "Interview Scheduled",
            items: [],
        },
        [uuid()]: {
            name: "Accepted",
            items: [],
        },
        [uuid()]: {
            name: "Rejected",
            items: [],
        },
    };

    const [columns, setColumns] = useState(columnsFromBackend);
    console.log(columns); // logs the columns with its content

CodePudding user response:

The columns state variable is initialized with the value of columnsFromBackend on the initial render. On subsequent renders (like when the API data returns, resulting in the effect calling setDataFromApi), columnsFromBackend is updated with the new value of dataFromApi, but the state value columns is not. This is how useState works. The argument passed to useState provides an initial value, but changes to that initialization value do not automatically flow through. The only way the state value gets updated, columns in this case, is by calling setColumns. You could add another effect to synchronize columns with dataFromApi, but I'd propose something like this instead (I'm assuming you want the uuid's you're generating to be stable across renders):

const [dataFromApi, setDataFromApi] = useState([]);
const [uuids] = useState(() => ({
    canvaUuid: uuid(),
    microsoftUuid: uuid(),
    inProgressUuid: uuid(),
    clApproveUuid: uuid(),
    clDeclinedUuid: uuid(),
    awaitingResponseUuid: uuid(),
    interviewScheduledUuid: uuid(),
    acceptedUuid: uuid(),
    rejectedUuid: uuid(),
}));

useEffect(() => {
    getLeadsClApproved().then((resp) => {
        setDataFromApi(resp.data);
    });
}, []);

const columns = React.useMemo(() => {
    const hardCodedData = [
        {
            id: uuids.canvaUuid,
            business_name: "Canva",
            first_name: "Melanie",
            last_name: "Perkins",
            created_at: "15th of Nov., 2022",
        },
        {
            id: uuids.microsoftUuid,
            business_name: "Microsoft",
            first_name: "Bill",
            last_name: "Gates",
            created_at: "15th of Nov., 2022",
        },
    ];
    return {
        [uuids.inProgressUuid]: {
            name: "In Progress",
            items: hardCodedData,
        },
        [uuids.clApproveUuid]: {
            name: "CL Approved",
            items: dataFromApi,
        },
        [uuids.clDeclinedUuid]: {
            name: "CL Declined",
            items: [],
        },
        [uuids.awaitingResponseUuid]: {
            name: "Awaiting Response",
            items: [],
        },
        [uuids.interviewScheduledUuid]: {
            name: "Interview Scheduled",
            items: [],
        },
        [uuids.acceptedUuid]: {
            name: "Accepted",
            items: [],
        },
        [uuids.rejectedUuid]: {
            name: "Rejected",
            items: [],
        },
    };
}, [uuids, dataFromApi]);

console.log(columns); // logs the columns with its content

Using useMemo here instead of useState guarantees that columns will always be in sync with dataFromApi.

  • Related