反应-使用useEffect和async setState导致其他重新渲染

时间:2020-07-19 08:41:49

标签: reactjs promise react-hooks

我在这里有一个React钩子

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 };
};

我要实现的目标-每当resourceName进行更改时,都需要刷新并调用所有不同的环境(dev, stage and prod),并返回最新的allEnvDetails。应该避免其他重新渲染

理想情况下,应该只有3个axios.get调用对应于3个环境。但是,它被称为9次(每个环境3次)。

根据this SO question,我在一个promise resolve / reject块中使用setState,因此,每当功能组件(我的钩子)中的状态更新时,都会触发另一个不需要的重新渲染。

是否有更好的方法来重构/解决此问题?我已经搜索了一段时间,但不确定是否可以改进。

2 个答案:

答案 0 :(得分:0)

您可以尝试在函数开始时添加条件if(isLoading):

`
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]);

`

答案 1 :(得分:0)

尝试以下代码:

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 };
};