ts/react - useEffect 中的 fetch 被多次调用

时间:2021-03-18 08:18:39

标签: reactjs typescript fetch

在我的功能组件中,我想在组件安装后获取数据。但不幸的是,该请求被触发了 3 次,直到它停止。你能告诉我为什么吗?

 const [rows, setRows] = useState<any[]>([]);
 const [tableReady, setTableReady] = useState<boolean>(false);
 const [data, setData] = useState<any[]>([]);


const getData = async () => {
      const user = await Amplify.Auth.currentAuthenticatedUser();
      const token = user.signInUserSession.idToken.jwtToken;
      const apiurl = 'xxx';

      fetch(apiurl, {
           method: 'GET',
           headers: {
                'Authorization': token
           }
      })
           .then(res => res.json())
           .then((result) => {
                setData(result);
           })
           .catch(console.log)
 }

 useEffect(() => {
      if (!tableReady) {
           getData();

           if (data.length > 0) {
                data.forEach((element, i) => {
                     const convertedId: number = +element.id;
                     setRows(rows => [...rows, (createData(convertedId, element.user))]);
                });
                setTableReady(true);
           }
      }
 }, []);

 return (
      <div className={classes.root}>
           <MUIDataTable
                title={""}
                data={rows}
                columns={columns}
           />
      </div>
 );

由于评论,我更新了我的问题。

1 个答案:

答案 0 :(得分:3)

useEffect 缺少依赖数组,因此每次组件呈现时都会调用其回调。

解决方案

添加依赖数组。

useEffect(() => {
  if (!tableReady) {
    getData();

    if (data.length > 0) {
      data.forEach((element, i) => {
        const convertedId: number = +element.id;
        rows.push(convertedId);
      });
      setTableReady(true);
    }
  }
}, []); // <-- dependency array

一个空的依赖数组会在组件挂载时运行一次效果。如果您希望它在任何特定值更新时运行,请将它们添加到依赖项数组中。

Conditionally firing an effect

编辑

似乎不需要存储 data 状态,因为它用于填充 rows 状态。由于 React 状态更新是异步处理的,并且 useEffect 回调是 100% 同步的,因此当您调用 getData 并且不等待 data 填充时,其余的效果回调正在使用最初为空的 data 数组。

我建议从 fetch 返回 getData 请求,然后将响应数据直接处理为您的 rows 状态。

const getData = async () => {
  const user = await Amplify.Auth.currentAuthenticatedUser();
  const token = user.signInUserSession.idToken.jwtToken;
  const apiurl = 'xxx';

  return fetch(apiurl, {
    method: 'GET',
    headers: {
      'Authorization': token
    }
  });  
}

useEffect(() => {
  if (!tableReady) {
    getData()
      .then(res => res.json())
      .then(data => {
        if (data.length) {
          setRows(data.map(element => createData(+element.id, element.user)))
        }
      })
      .catch(console.error)
      .finally(() => setTableReady(true));
  }
}, []);