已使用useCallback和useEffect,为何我的React组件仍渲染4次?
React组件渲染时机解析及代码优化
作为React初学者,我尝试使用Axios获取数据,通过useState管理加载、错误、数据状态,结合useEffect和useCallback控制请求逻辑,并添加了console.log("hey")来追踪组件的渲染时机,代码如下:
import { useCallback, useState, useEffect } from "react"; import DriversList from "./components/DriversList"; import axios from "axios"; function App() { const [drivers, setDrivers] = useState([]); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const apiGetDataHandler = useCallback(() => { setIsLoading(true); setError(null); axios .get("http://ergast.com/api/f1/2022/drivers.json?limit=25") .then((response) => { setIsLoading(false); setDrivers(response.data.MRData.DriverTable.Drivers); }) .catch((error) => { setError(error.message); }); }, []); useEffect(() => { apiGetDataHandler(); }, [apiGetDataHandler]); let content = <DriversList drivers={drivers} />; console.log("hey"); if (error) { content = <p>{error}</p>; } if (isLoading) { content = <p>Loading...</p>; } return ( <> <section>{content}</section> </> ); } export default App;
渲染次数拆解
你会看到console.log("hey")总共输出3次,对应以下渲染场景:
- 初始挂载渲染:组件第一次加载时执行,这是首次输出。
- 加载状态更新渲染:调用
apiGetDataHandler后,setIsLoading(true)触发状态变更,组件重新渲染,第二次输出。 - 请求完成后渲染:
- 请求成功时,
setIsLoading(false)和setDrivers(...)会被React批量处理,触发一次渲染,第三次输出; - 请求失败时,
setError(error.message)触发渲染,同样是第三次输出(原代码这里遗漏了setIsLoading(false),会导致加载状态一直存在,需要补上)。
- 请求成功时,
代码优化点
- 修复请求失败的加载状态:在
catch块中添加setIsLoading(false),避免请求失败后页面一直显示加载:
.catch((error) => { setIsLoading(false); setError(error.message); });
- useCallback的合理使用:当前
apiGetDataHandler的依赖为空数组,确保函数只会在组件初始挂载时创建一次,useEffect也只会执行一次,符合仅触发一次数据请求的需求,这个用法是正确的。
内容的提问来源于stack exchange,提问作者glpsx
相关产品推荐
相关产品推荐

