React自定义Hook首次渲染返回空数组问题求助
问题解决方法
核心问题分析
- Driver组件的useEffect未监听数据更新:你的
useEffect依赖项是空数组,仅在组件首次挂载时执行一次,此时useDriversData还未完成数据请求,返回空数组,导致setDriver找不到对应车手。后续Hook拿到完整数据后,useEffect不会重新触发,所以state一直是空的。 - 自定义Hook的数据计算未关联状态更新:
driverListApiData是每次Hook渲染时重新创建的数组,但没有依赖接口返回的driver状态,导致接口数据更新后,拼接的车手数据不会同步更新。
第一步:修复自定义Hook useDriversData
把拼接数据的逻辑用useMemo包裹,依赖接口返回的状态,确保数据更新时重新计算:
import { useState, useEffect, useMemo } from "react"; import { getDriversStandings } from "../services/reqester"; export const useDriversData = () => { const [apiDrivers, setApiDrivers] = useState([]); useEffect(() => { getDriversStandings().then((result) => { setApiDrivers(result.MRData.StandingsTable.StandingsLists); }); }, []); // 用useMemo缓存拼接后的车手数据,仅当apiDrivers变化时重新计算 const driverListApiData = useMemo(() => { const list = []; // 遍历接口返回的车手数据 apiDrivers.forEach((driverData) => { if (driverData.DriverStandings) { driverData.DriverStandings.forEach((data) => { const baseData = { id: data.Driver.driverId, position: data.position, points: data.points, team: data.Constructors[0].name, firstName: data.Driver.givenName, lastName: data.Driver.familyName, }; // 根据driverId补充额外数据 if (data.Driver.driverId === "max_verstappen") { list.push({ ...baseData, racingNumber: "https://media.formula1.com/d_default_fallback_image.png/content/dam/fom-website/2018-redesign-assets/drivers/number-logos/MAXVER01.png.transform/2col-retina/image.png", nationImg: "https://media.formula1.com/d_default_fallback_image.png/content/dam/fom-website/flags/Netherlands.jpg.transform/2col-retina/image.jpg", driverImg: "https://media.formula1.com/d_driver_fallback_image.png/content/dam/fom-website/drivers/M/MAXVER01_Max_Verstappen/maxver01.png.transform/2col-retina/image.png", driverProfileImg: "https://media.formula1.com/content/dam/fom-website/drivers/2023Drivers/verstappen.jpg.img.1024.medium.jpg/1677069646195.jpg", podiums: "80", maxPoints: "2080.5", grandPrixEntry: "166", worldChampionships: "2", highestPosition: "1", placeBirth: "Hasselt, Belgium", }); } else if (data.Driver.driverId === "perez") { list.push({ ...baseData, racingNumber: "https://media.formula1.com/d_default_fallback_image.png/content/dam/fom-website/2018-redesign-assets/drivers/number-logos/SERPER01.png.transform/2col-retina/image.png", nationImg: "https://media.formula1.com/d_default_fallback_image.png/content/dam/fom-website/flags/Mexico.jpg.transform/2col-retina/image.jpg", driverImg: "https://media.formula1.com/d_driver_fallback_image.png/content/dam/fom-website/drivers/S/SERPER01_Sergio_Perez/serper01.png.transform/2col-retina/image.png", }); } // 可继续添加其他车手的判断逻辑 }); } }); return list; }, [apiDrivers]); // 依赖apiDrivers,数据更新时重新计算 return driverListApiData; };
第二步:修复Driver组件
去掉多余的state,直接基于Hook返回的数据进行查找,同时处理加载状态:
import React from "react"; import { useParams } from "react-router-dom"; import { useDriversData } from "../../hooks/useDriversData"; const Driver = () => { const driverListApiData = useDriversData(); const { id } = useParams(); // 直接查找对应车手 const driver = driverListApiData.find(data => data.id === id); // 数据未加载或未找到车手时显示对应状态 if (!driverListApiData.length) { return <div>加载中...</div>; } if (!driver) { return <div>未找到该车手</div>; } return ( <div className="driver-main-container"> <div className="listing-container"> <img src={driver.driverProfileImg} alt={`${driver.firstName} ${driver.lastName}`} /> </div> {/* 可添加更多车手详情内容 */} </div> ); }; export default Driver;
为什么之前的方法无效?
- 你用
await driverListApiData是无效的,因为driverListApiData是React状态,不是Promise,不能用await等待。 - 重新保存时组件热重载,此时Hook已经拿到了数据,所以渲染正常,但首次挂载时数据还没加载完成,导致state为空。
内容的提问来源于stack exchange,提问作者Mario Angelov
相关产品推荐
相关产品推荐

