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

React中API请求文件分离:解决Invalid hook call错误

问题原因

你遇到的「Invalid hook call」错误,核心原因是React Hook(比如useState)只能在React组件的顶层,或者命名以use开头的自定义Hook中调用,而你写的GetUsers是普通函数,完全不符合Hook的使用规则。

正确设计方案

下面提供两种最常用的合理实现方式,你可以根据业务场景选择:


方案1:API层与状态层分离(推荐通用场景)

把Api.js做成纯请求工具,只负责发送请求和处理响应格式,状态管理交给React组件自己完成。

改造Api.js(纯请求函数)

// Api.js
import axios from "axios";

// 统一封装API请求,返回Promise供组件处理
export const getUsers = () => {
  return axios.get("http://localhost:8080/api/Users", {
    headers: {
      "x-access-token": localStorage.getItem("token"),
      "Content-Type": "application/json"
    }
  })
  .then(res => {
    if (res.statusText === "OK") {
      return res.data;
    }
    // 请求成功但状态不符合预期,抛出错误
    throw new Error(`请求异常: ${res.statusText}`);
  })
  .catch(err => {
    console.error("请求错误: ", err);
    // 抛出错误让组件捕获处理
    throw err;
  });
};

改造ShowData.js(组件内管理状态)

// ShowData.js
import { useEffect, useState } from "react";
import { getUsers } from "./Api";

const Properties = () => {
  // 组件内声明状态,管理数据、加载状态、错误信息
  const [users, setUsers] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);

  useEffect(() => {
    // 用async/await处理异步请求
    const fetchUsers = async () => {
      setIsLoading(true);
      try {
        const userData = await getUsers();
        setUsers(userData);
      } catch (err) {
        setError(err.message);
      } finally {
        setIsLoading(false);
      }
    };

    fetchUsers();
  }, []);

  // 根据状态渲染不同内容
  if (isLoading) return <div>加载中...</div>;
  if (error) return <div>出错了: {error}</div>;

  return (
    <div>
      <h2>用户列表</h2>
      <ul>
        {users.map(user => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    </div>
  );
};

export default Properties;

方案2:封装成自定义Hook(适合复用场景)

如果多个组件都需要调用该接口,且都要处理加载、错误、数据状态,可以把逻辑封装成自定义Hook,实现状态逻辑复用。

创建自定义Hook(useUsers.js)

// useUsers.js
import { useState, useEffect } from "react";
import axios from "axios";

// 自定义Hook必须以use开头
export const useUsers = () => {
  const [users, setUsers] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchUsers = async () => {
      setIsLoading(true);
      try {
        const res = await axios.get("http://localhost:8080/api/Users", {
          headers: {
            "x-access-token": localStorage.getItem("token"),
            "Content-Type": "application/json"
          }
        });
        if (res.statusText === "OK") {
          setUsers(res.data);
        } else {
          throw new Error(`请求异常: ${res.statusText}`);
        }
      } catch (err) {
        setError(err.message);
        console.error("请求错误: ", err);
      } finally {
        setIsLoading(false);
      }
    };

    fetchUsers();
  }, []);

  // 返回状态和数据供组件使用
  return { users, isLoading, error };
};

在组件中使用自定义Hook

// ShowData.js
import { useUsers } from "./useUsers";

const Properties = () => {
  // 直接调用自定义Hook获取状态
  const { users, isLoading, error } = useUsers();

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

  return (
    <div>
      <h2>用户列表</h2>
      <ul>
        {users.map(user => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    </div>
  );
};

export default Properties;

额外注意点
  1. 原代码中存在命名不一致问题:GetUsers(大驼峰)和调用时的getUsers(小驼峰),已在修正代码中统一为小驼峰(符合JS函数命名规范)。
  2. 原Promise的then块语法有误(else位置错误),已在修正代码中修复。

内容的提问来源于stack exchange,提问作者J.D.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 03:20:15