I'm trying to process some api data on useEffect and while processing data I need to set it on various states, while processing the data, for some reasons useEffect is getting triggered infinitely. Although from the class components I'm aware of setState being an asynchronous action which is not waiting for the completion of forEach. Do we have any workaround for functional components.
useEffect(() => {
const apiResponse = fetchAppName();
apiResponse.then(
(response) => {
// if (response.statusCode === '200' && response.status.statusType === 'SUCCESS' && response.data) {
const dataFields = {};
const appNameValues = [];
dummyData.data.forEach((ele) => {
const workFlowIds = [];
ele.workflowConfigs.forEach((wc) => {
workFlowIds.push(wc.workflowId);
})
dataFields[ele.name] = workFlowIds;
});
Object.keys(dataFields).forEach((k) => {
appNameValues.push(k);
});
setAppData(dataFields);
setDropDownOptions({
...dropDownOptions,
appName: appNameValues,
});
// }
}).catch((e)=>{
console.log('Failed to fetchAppNames due to: ', e);
});
},[setDropDownOptions, dropDownOptions]);
Don't use a dependency that is updated by the effect. In other words, dropDownOptions
is a dependency and the effect updates it, thus creating a render loop.
The state updater function is stable, so it's unnecessary, and use a functional state update to remove the other dropDownOptions
dependency.
Note
React guarantees that setState function identity is stable and won’t change on re-renders. This is why it’s safe to omit from the useEffect or useCallback dependency list.
useEffect(() => {
const apiResponse = fetchAppName();
apiResponse.then(
(response) => {
// if (response.statusCode === '200' && response.status.statusType === 'SUCCESS' && response.data) {
const dataFields = {};
const appNameValues = [];
dummyData.data.forEach((ele) => {
const workFlowIds = [];
ele.workflowConfigs.forEach((wc) => {
workFlowIds.push(wc.workflowId);
})
dataFields[ele.name] = workFlowIds;
});
Object.keys(dataFields).forEach((k) => {
appNameValues.push(k);
});
setAppData(dataFields);
setDropDownOptions(dropDownOptions => ({
...dropDownOptions,
appName: appNameValues,
}));
// }
}).catch((e)=>{
console.log('Failed to fetchAppNames due to: ', e);
});
},[]); // will run on mount, add other dependency triggers if needed.