5

I have a React hook here

export const useConfigDetails = (resourceName: string) => {
  const [isLoading, setLoading] = React.useState<boolean>(true);
  const [error, setError] = React.useState<AxiosError>(undefined);
  const [allEnvDetails, setAllEnvDetails] = React.useState<ResourceDetails[]>();


  React.useEffect(() => {
   const configPromises = ['dev', 'stage', 'prod'].map((environment: Environment) =>
    axios.get('someUrlGetEndpoint'));

    Promise.all(configPromises)
      .then((resp: ResourceDetails[]) => setAllEnvDetails(resp))
      .catch((err: AxiosError) => setError(err))
      .finally(() => setLoading(false));
  }, [resourceName]);

  return { allEnvDetails, isLoading };
};

What I am trying to achieve - Whenever the resourceName changes, it will need to refresh and make calls to all different environments (dev, stage and prod), and return the latest allEnvDetails back. It should avoid other re-renders

Ideally, there should only be 3 axios.get calls that correspond to the 3 environments. However, it's being called 9 times (3 times for each environment).

According to this SO question, I am using the setState within a promise resolve/reject block, so whenever state within the functional component (my hook) is updated it will trigger another, unwanted re-render.

Is there a better way to refactor/resolve this issue? I had been searching for a while, but I'm not sure what can be improved.

Ed Lucas
  • 5,955
  • 4
  • 30
  • 42
Christie Chen
  • 185
  • 1
  • 5
  • 15
  • 2
    you have three state for initial ( 3 renders) which will double the re-renders due to `React.strictMode` and 3 more after component did mount so it becomes 9, here to answer https://stackoverflow.com/questions/62258852/react-component-render-twice-using-usestate – Ericgit Jul 19 '20 at 08:57

2 Answers2

0

you can try to add condition if(isLoading) in begining of function:

`
React.useEffect(() => {
if(isLoading){
const configPromises = ['dev', 'stage', 'prod'].map((environment: 
Environment) =>
axios.get('someUrlGetEndpoint'));

Promise.all(configPromises)
  .then((resp: ResourceDetails[]) => setAllEnvDetails(resp))
  .catch((err: AxiosError) => setError(err))
  .finally(() => setLoading(false));
}
}, [resourceName]);

`

Adel.D
  • 41
  • 5
0

Try this code:

export const useConfigDetails = (resourceName: string) => {
  const [isLoading, setLoading] = React.useState<boolean>(true);
  const [error, setError] = React.useState<AxiosError>(undefined);
  const [allEnvDetails, setAllEnvDetails] = React.useState<ResourceDetails[]>();


  React.useEffect(() => {
      (async () => {
          try{
              setLoading(true)

              const dev = await axios.get('someUrlGetEndpoint');
              const stage = await axios.get('someUrlGetEndpoint');
              const prod = await axios.get('someUrlGetEndpoint');

              setAllEnvDetails([
                  dev,
                  stage,
                  prod
              ])

              setLoading(false)
          }catch(e) {
              setError(e);
              setLoading(false)
          }
      })()
  }, [resourceName]);

  return { allEnvDetails, isLoading };
};
Ali Torki
  • 1,929
  • 16
  • 26