Home > Mobile >  useFetch hook based on use cases causes infinite loop
useFetch hook based on use cases causes infinite loop

Time:05-20

I tried to create a useFetch hook based on diferent use-case and I can't deal with this task.

First of all, I have a service, a repository and then call a use-case:

const userService = new UserServiceImpl(apiConfig);
const uploadImageService = new AmplifyS3Service();
const userRepository = new UserRepositoryImpl(
   userService,
   uploadImageService
);
const getUserUseCase = new GetUserUseCaseImpl(userRepository);

I would like to optimize every tasks, fetch data from getUserUseCase because returns a Promise, put on the state and map trough data. My whole application is based on use-cases

const [user, setUser] = useState<User>();
getUserUseCase.getUser().then(setUser)

I tried to create a useFetch hook:

import { useEffect, useState } from "react";

export const useFetch = (useCase: Promise<any>) => {
  const [state, setState] = useState({
    data: null,
    loading: true,
    error: null,
  });

  useEffect(() => {
    useCase.then((data) => {
      setState({
        data,
        loading: false,
        error: null,
      });
    });
  }, [useCase]);

  return state;
};

and then I call it passing a use-case by argument...

const userInfo = getUserUseCase.getUser();
const { data, loading } = useFetch(userInfo);

after this point, I get a infinite loop, and I don't know which part I'm doing wrong.
Any help will be appreciate.
Thanks!

CodePudding user response:

I'm guessing that everytime this runs, a new promise object is returned:

const userInfo = getUserUseCase.getUser();

Which you then pass to useFetch:

const { data, loading } = useFetch(userInfo);

Which is then used as an effect dependency:

  useEffect(() => {
    useCase.then((data) => {
      setState({
        data,
        loading: false,
        error: null,
      });
    });
  }, [useCase]);

Which means that each render that effect is getting triggered, because on each render the effect dependencies have changed.


I'm guessing then, that you do not want this to run on every render:

const userInfo = getUserUseCase.getUser();

Which means you should memoize it so it always has the same value each render and only runs once.

const userInfo = useMemo(() => getUserUseCase.getUser());

Now userInfo has stable identity and can safely be used as an effect depedency.

CodePudding user response:

Nuke the useEffect Hook inside useFetch. I think what is happening here is useCase changes every time it re-renders so this triggers an infinite loop.

export const useFetch = (useCase: Promise<any>) => {
  const [state, setState] = useState({
    data: null,
    loading: true,
    error: null,
  });

  useCase.then((data) => {
    setState({
      data,
      loading: false,
      error: null,
    });
  });

  return state;
};
  • Related