Reputation: 35
I'm trying to get a list of array items from an api response using useEffect, as a result I'm getting a list of objects. I want to convert that using Objects.key() method, but when I iterate through it, values won't be printed on view page. The response keeps on returning the call from api response.
API CALL
export function getServicesById(facility_id) {
return axios
.get(`${baseURL}patients/appointments/1`)
.then((response) => {
if(response.status===200){
// console.log(response.data)
return response
}
}).catch(error => {
console.log('error', error)
return error
});
}
useEffect to get response data
useEffect(() => {
getServicesById()
.then((res) => {
setResponseData(res.data);
})
.catch((error) => {
console.log(error);
});
// console.log('data is', newResponseData);
}, [responseData, setResponseData]);
Converting objects to array items
const newResponseData = Object.keys(responseData).reduce((array, key) => {
return [...array, { key: responseData[key] }];
}, []);
Jsx page where I'm rendering the data
<TableBody>
{newResponseData &&
newResponseData.map((serv, index) => (
<TableRow key={index}>
<TableCell align="left" data-label="Action">
<Field
name="status"
component={renderSelectInput}
variant="outlined"
size="small"
className="fileds"
inputClass="sm-filed"
>
<MenuItem selectedValue="progress">
In progress
</MenuItem>
<MenuItem value="closed">
Closed
</MenuItem>
</Field>
</TableCell>
<TableCell data-label="Id">{serv.id}</TableCell>
<TableCell data-label="Patient name">{serv.patient_name}</TableCell>
<TableCell data-label="Test Name">{serv.test_name}</TableCell>
</TableRow>
))}
</TableBody>
Upvotes: 2
Views: 1303
Reputation: 202628
You are using an useEffect
dependency that the effect updates:
useEffect(() => {
getServicesById()
.then((res) => {
setResponseData(res.data);
})
.catch((error) => {
console.log(error);
});
}, [responseData, setResponseData]);
responseData
is updated by the effect, and when updated will trigger another rerender and the effect will run again. You likely only want to fetch the data once when the component mounts.
Another potential issue I see is that the newResponseData
array has objects with only a key
key.
const newResponseData = Object.keys(responseData).reduce((array, key) => {
return [...array, { key: responseData[key] }];
}, []);
But in the render you are attempting to access id
, patient_name
, and test_name
properties. These are undefined since { key: responseData[key] }
hasn't any of these properties.
Remove the useEffect
dependencies so the effect runs once on component mount. Since I also think you meant to compute an array of the object values from responseData
to map in your UI, you can do this once before sending the data to state.
useEffect(() => {
getServicesById()
.then((res) => {
const data = Object.values(res.data)
setResponseData(data);
})
.catch((error) => {
console.log(error);
});
}, []);
Then just map your responseData
state:
<TableBody>
{responseData && responseData.map((serv, index) => (
<TableRow key={index}>
<TableCell align="left" data-label="Action">
<Field
name="status"
component={renderSelectInput}
variant="outlined"
size="small"
className="fileds"
inputClass="sm-filed"
>
<MenuItem selectedValue="progress">
In progress
</MenuItem>
<MenuItem value="closed">
Closed
</MenuItem>
</Field>
</TableCell>
<TableCell data-label="Id">{serv.id}</TableCell>
<TableCell data-label="Patient name">{serv.patient_name}</TableCell>
<TableCell data-label="Test Name">{serv.test_name}</TableCell>
</TableRow>
))}
</TableBody>
Upvotes: 1
Reputation: 2695
In addition to the above answer by Drew Reese, Please remove responseData from useEffect params as you are using setResponseData inside it and useEffect gets triggered on every state change :
useEffect(() => {
getServicesById()
.then((res) => {
setResponseData(res.data);
})
.catch((error) => {
console.log(error);
});
}, [setResponseData]);
Upvotes: 1