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

如何在Fetch请求API时设置额外状态?自定义Hook列空数组问题

问题解决:自定义Hook useTable初始化时columns为空的处理

核心问题分析

  1. 异步请求时序问题:API请求是异步执行的,Hook初始化后会立刻返回初始状态的columns(你代码里初始为undefined),直到请求完成才会更新columns。
  2. 代码冗余与潜在风险:
    • useRef的使用完全多余,直接在useEffect里调用loadDatabase即可。
    • 未处理API返回空数组的情况,d[0]会直接导致报错。
    • data状态从未被更新,Hook返回的data && data[actualcategory]始终是undefined。

修复后的代码

const urls: string[] = [
  "https://jsonplaceholder.typicode.com/posts",
  "https://jsonplaceholder.typicode.com/comments",
  "https://jsonplaceholder.typicode.com/albums",
  "https://jsonplaceholder.typicode.com/photos",
  "https://jsonplaceholder.typicode.com/todos",
];

// 补充类型定义(若未定义)
type Column = {
  col: {
    title: string;
    disp: boolean;
  };
};

type DataItem = Record<string, any>;

const useTable = (idurl: number, actualcategory: string) => {
  // 给columns设置初始空数组,避免返回undefined
  const [columns, setColumns] = useState<Column[]>([]);
  const [data, setData] = useState<DataItem[]>([]);
  // 新增加载/错误状态,方便外部组件处理对应场景
  const [isLoading, setIsLoading] = useState<boolean>(true);
  const [error, setError] = useState<string | null>(null);

  const loadDatabase = async () => {
    setIsLoading(true);
    setError(null);
    try {
      const response = await fetch(urls[idurl]);
      if (!response.ok) throw new Error('请求失败');
      const d = await response.json() as DataItem[];
      
      if (d.length === 0) {
        setColumns([]);
        setData([]);
        return;
      }

      // 生成columns配置
      const newColumns = Object.keys(d[0]).map(title => ({
        col: { title, disp: true }
      }));
      setColumns(newColumns);
      setData(d);
    } catch (err) {
      setError(err instanceof Error ? err.message : '未知错误');
      setColumns([]);
    } finally {
      setIsLoading(false);
    }
  };

  useEffect(() => {
    loadDatabase();
  }, [idurl, actualcategory]); // 补充idurl到依赖项,确保URL变化时重新请求

  return {
    tableData: data,
    columns,
    isLoading,
    error
  } as const;
};

export { useTable };

关键优化点

  • 初始值明确化:给columns初始化为空数组[],确保Hook初始化时返回的是明确的空数组而非undefined。
  • 状态补充:新增isLoading和error状态,让使用Hook的组件能处理加载中、错误场景。
  • 依赖项修复:useEffect依赖数组加上idurl,当请求的URL变化时自动重新发起请求。
  • 异常处理:处理HTTP请求失败、返回空数组的情况,避免代码崩溃。
  • 冗余代码移除:删掉不必要的useRef,简化逻辑。

使用示例

const MyTable = () => {
  const { tableData, columns, isLoading, error } = useTable(0, 'posts');

  if (isLoading) return <div>加载中...</div>;
  if (error) return <div>错误:{error}</div>;

  return (
    <table>
      <thead>
        <tr>
          {columns.map((col, idx) => (
            col.col.disp && <th key={idx}>{col.col.title}</th>
          ))}
        </tr>
      </thead>
      <tbody>
        {tableData.map((row, rowIdx) => (
          <tr key={rowIdx}>
            {columns.map((col, colIdx) => (
              col.col.disp && <td key={colIdx}>{row[col.col.title]}</td>
            ))}
          </tr>
        ))}
      </tbody>
    </table>
  );
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 12:15:41