Home > Mobile >  Infinite loop in useEffect after an API mock in Jest
Infinite loop in useEffect after an API mock in Jest

Time:06-14

Seeing some weird things within the component that I am currently working on. So, I am having a server side paginated table, On every API call I am pushing the new records to the existing array. I am using fetchBaseQuery to make an API call.

Code to achieve it

let response = useGetQuery(request); // This hook will perform the API call
const records =
    response.data?.records;
  React.useEffect(() => {
    if (records) {
      setTableRecords((prevState: any) => [
        ...prevState,
        ...records,
      ]);
    }
  }, [records]);

Test case for this


jest.mock("../endpoints", () => ({
  ...jest.requireActual("../endpoints"),
  useGetQuery: () => ({
    isSuccess: true,
    data: {
      message: "Success",
      records: [], // It gets into infinte loop if I provide this key while mocking
    },
  }),
}));

test("should mount", () => {
    const component = renderer.create(<SomeComponent/>);
    const tree = component.toJSON();
    expect(tree).toMatchSnapshot();
});

As, per my understanding if we use array as a dependency in the useEffect hook, it might lead to an infinite loop as React uses shallow comparison to check if the dependency’s reference has changed. To fix this, I tried using useRef hook, but that doesn't work as per my use case as useRef doesn’t notify you when its content changes.

I then tried by making the response.data object as a dependency to the useEffect hook, but as per the shallow comparison it is also leading to the infinite loop, so I was then trying to fix it with useMemo hook but got no luck as if I pass the dependency as the object it was again leading to the same problem & passing no dependency doesn't work for me.

Is there any other way that I can handle this situation better?

CodePudding user response:

I use the useEffect hook, but instead of passing the api response as an array, I use some parameter, for example if I call an api to get images based on a category, I will only call the api when the category changes:

   const [state, setState] = useState({
      loading: true,
      data: [],
   });

   useEffect(() => {
       myApiMethod(category).then((gifs) => {
          setState({
             loading: false,
             data: gifs,
          });
       });
   }, [category]);

CodePudding user response:

Stringify the Array that you are passing in the dependency array if the array is not too large.

let response = useGetQuery(request); // This hook will perform the API call
const records =
    response.data?.records;
  React.useEffect(() => {
    if (records) {
      setTableRecords((prevState: any) => [
        ...prevState,
        ...records,
      ]);
    }
  }, [JSON.stringify(records)]);
  • Related