Why this code makes infinite loop in react. here the useEffect with data and columnDataWithTaskProperty cause the infinite loop but i don’t know why
const useBoard = () => {
const { data: columnData } = useGetColumnQuery();
const { data } = useGetTaskAccordingToStatus();
const [columnDataWithTaskProperty, setColumnDataWithTaskProperty] = useState(
[]
);
const [finalState, sFinalState] = useState([]);
useEffect(() => {
const allColumns = columnData?.data?.map((item) => ({
name: item.name,
_id: item._id,
tasks: [],
}));
setColumnDataWithTaskProperty(allColumns);
}, [columnData]);
useEffect(() => {
console.log("meeee data deps");
const updatedColumns = columnDataWithTaskProperty.map((column) => ({
...column,
tasks: data.flat().filter((task) => task.status === column.name),
}));
sFinalState(updatedColumns);
}, [columnDataWithTaskProperty, data]);
return {
finalState,
};
};
here is how i’m fetching the data using useGetTaskAccordingToStatus. for fetching data i’m using the react query.
const useGetTaskAccordingToStatus = () => {
const { active_project } = useSelector(projectDataInStore);
const userQueries = useQueries({
queries: statesOfTaskManager.map((status) => {
return {
queryKey: [status, active_project],
queryFn: () =>
customAxiosRequestForGet("/task", {
status,
projectName: active_project,
}),
onSuccess: ({ data }) => {
return data;
},
};
}),
});
const data = userQueries?.map((item) => item?.data?.data);
return { data };
};
3
Answers
I suggest you using only one use effect and remove columnDataWithTaskProperty for testing sack, you may return it later on.
here’s an example of my suggestion, but can’t test it without actual data
could you please examine the changes on "check" in this:
Haven’t tested this method but I think using an object that is not instantiated as a useState causes this kind of issues when used as a dependency on a useEffect. Using the object as a useState object helps React’s useEffect keep track of the changes and prevents those kind of issues.
Try this solution:
The problem you are encountering is actually a problem in
useGetTaskAccordingToStatus
. This hook returns a new object each render, therefore triggering the effects each time.The solution should be to wrap the
map
inside that hook inuseMemo
:Assuming
useQueries
returns a stable array (only changing it when the query results change), theuseMemo
should fix your problem by only running themap
when the data actually changes.Additionally,
useMemo
is actually the correct hook to use in youruseBoard
hook instead ofuseEffect
. You want to calculate something based on the state, not synchronize with an external system.This has the benefit of calculating the values directly when the dependencies change,
useEffect
only runs after render, so the old hook withuseEffect
should actually cause multiple rerenders when the data changes, theuseMemo
variant only one rerender.