【问题标题】:React - useEffect with async setState causing additional re-rendersReact - 带有异步 setState 的 useEffect 导致额外的重新渲染
【发布时间】:2020-11-08 16:20:32
【问题描述】:

我这里有一个 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,所以每当功能组件(我的钩子)中的状态更新时,它都会触发另一个不需要的重新渲染。

有没有更好的方法来重构/解决这个问题?我一直在寻找一段时间,但我不确定有什么可以改进的。

【问题讨论】:

  • 您有三个初始状态(3 个渲染),由于React.strictMode 和组件安装后的重新渲染增加了一倍,所以它变成了 9,这里回答 stackoverflow.com/questions/62258852/…跨度>

标签: reactjs promise react-hooks


【解决方案1】:

您可以尝试在函数开头添加条件 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]);

`

【讨论】:

    【解决方案2】:

    试试这个代码:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-09
      • 2020-09-12
      • 1970-01-01
      • 1970-01-01
      • 2022-01-12
      • 2019-09-26
      • 2022-01-03
      • 2019-11-21
      相关资源
      最近更新 更多