You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React开发可复用API数据获取组件遇到的问题求解

解决方案

问题根源

  • 初始输出undefined:接口请求是异步操作,组件第一次渲染时请求尚未返回,自定义Hook返回的state初始值为undefined,请求完成后调用setTeams触发重渲染才会返回真实数据,属于正常的异步渲染逻辑。
  • TypeScript报错Object is possibly 'undefined':你定义的teamsstate类型为Teams[] | undefined,未判空直接调用map方法时,TS会检测到潜在的调用undefined方法的风险,因此抛出类型错误。
  • 额外隐藏问题:你在App组件中写的map回调使用了大括号但没有return语句,就算数据正常也无法渲染出列表项。

修复后的代码

1. 自定义Hook useGetTeamsByLeague.ts 优化

import axios from 'axios';
import { useEffect, useState } from 'react';

interface Teams {
    id: number;
    name: string;
    league: string;
    created_at: string;
    updated_at: string;
}

const useGetTeamsByLeague = (league: string) => {
    // 初始值设为空数组,类型固定为Teams[],不存在undefined情况
    const [teams, setTeams] = useState<Teams[]>([]);
    // 新增loading状态,用于渲染加载态
    const [loading, setLoading] = useState<boolean>(true);
    // 新增error状态,用于渲染错误提示
    const [error, setError] = useState<string | null>(null);

    useEffect(() => {
        // 新增请求取消逻辑,避免内存泄漏
        const controller = new AbortController();
        
        setLoading(true);
        setError(null);
        axios
            .get(`http://awaydays-api.cb/api/teams/${league}`, {
                signal: controller.signal
            })
            .then((response) => {
                setTeams(response.data);
            })
            .catch((err) => {
                // 忽略请求取消的报错
                if (!axios.isCancel(err)) {
                    console.log(err);
                    setError('队伍数据请求失败');
                }
            })
            .finally(() => {
                if (!controller.signal.aborted) {
                    setLoading(false);
                }
            });
        
        // 组件卸载时取消未完成的请求
        return () => controller.abort();
    }, [league]);

    // 导出三个状态,方便组件按需使用
    return { teams, loading, error };
};

export default useGetTeamsByLeague;

2. App组件调用修改

import useGetTeamsByLeague from './Hooks/useGetTeamsByLeague';
import './Reset.scss';

function App() {
    // 解构获取三个状态
    const { teams, loading, error } = useGetTeamsByLeague('Championship');
    console.log(teams);

    if (loading) return <div>加载中...</div>;
    if (error) return <div>{error}</div>;

    return (
        <div className='App'>
            <Header>
                {/* 箭头函数去掉大括号隐式返回,或者加return语句,同时添加key属性避免React警告 */}
                {teams.map(team => (
                    <li key={team.id}>{team.name}</li>
                ))}
            </Header>
        </div>
    );
}

export default App;

修复效果说明

  • TS报错直接消失:teams的类型固定为Teams[],永远不会是undefined,无需额外判空即可调用数组方法。
  • 异步逻辑更完善:新增的loading和error状态可以覆盖请求全流程的用户交互,不会出现初始空白或者报错崩溃的情况。
  • 避免内存泄漏:新增的请求取消逻辑解决了组件卸载后请求返回还调用setState的潜在问题。

内容的提问来源于stack exchange,提问作者CIB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 13:54:09