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?
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
.