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

React自定义TS Fetch Hook报错:Cannot read properties of null (reading 'useState')求助

解决方案:自定义Fetch Hook报错问题

一、核心报错原因排查(对应截图中的Hook调用错误)

你遇到的是React Hook的非法调用错误,常见触发场景及解决:

  • 禁止在非顶层调用Hook:确保useCustomFetch只能在函数组件的顶层或其他自定义Hook的顶层调用,不能放在if/else、for循环、嵌套函数或类组件中。
    错误示例:

    // 错误:条件判断内调用Hook
    function MyComponent() {
      if (isLoggedIn) {
        const { data } = useCustomFetch('/api/user', {});
      }
      return <div>...</div>;
    }
    

    正确示例:

    // 正确:组件顶层调用Hook
    function MyComponent() {
      const { data, loading, error } = useCustomFetch('/api/user', {});
      
      if (loading) return <div>加载中...</div>;
      if (error) return <div>错误:{(error as Error).message}</div>;
      
      return <div>{JSON.stringify(data)}</div>;
    }
    
  • 检查React版本与依赖一致性:

    1. 确保react和react-dom版本均≥16.8(Hook最低支持版本),且版本一致:
      npm list react react-dom
      
    2. 若版本不一致或存在多实例,执行以下命令修复:
      npm install react@latest react-dom@latest
      npm dedupe
      

二、修复自定义Hook的潜在问题

虽然不是当前报错的直接原因,但优化代码可避免后续问题:

  1. 启用customBase参数:原代码未使用该参数,补充URL拼接逻辑:
    const fullUrl = customBase ? `${customBase}${url}` : url;
    const response = await fetch(`${fullUrl}?${new URLSearchParams(params)}`);
    
  2. 添加正确的useEffect依赖项:当url/params/customBase变化时自动重新请求:
    useEffect(() => {
      getData();
    }, [url, params, customBase]);
    
    注意:若每次渲染都传递新的params对象,需用useMemo包裹避免无限重渲染:
    function MyComponent() {
      const params = useMemo(() => ({ page: '1', size: '10' }), []);
      const { data } = useCustomFetch('/api/list', params);
    }
    
  3. 避免组件卸载后的状态更新:添加请求取消逻辑防止内存泄漏:
    useEffect(() => {
      const controller = new AbortController();
      const signal = controller.signal;
    
      const getData = async () => {
        setLoading(true);
        try {
          const fullUrl = customBase ? `${customBase}${url}` : url;
          const response = await fetch(`${fullUrl}?${new URLSearchParams(params)}`, { signal });
          const json = await response.json();
          setStatus(response.status);
          setStatusText(response.statusText);
          setData(json);
        } catch (error) {
          // 忽略主动取消的请求错误
          if ((error as Error).name !== 'AbortError') {
            setError(error);
          }
        }
        setLoading(false);
      };
    
      getData();
      return () => controller.abort(); // 组件卸载时取消请求
    }, [url, params, customBase]);
    
  4. 优化TypeScript类型:替换any为泛型,提升类型安全性:
    export type FetchResponse<T = unknown> = {
      status: number;
      statusText: string;
      data: T | undefined;
      error: unknown;
      loading: boolean;
    };
    
    export const useCustomFetch = <T = unknown>(
      url: string,
      params: Record<string, string>,
      customBase?: string
    ): FetchResponse<T> => {
      const [status, setStatus] = useState<number>(0);
      const [statusText, setStatusText] = useState<string>('');
      const [data, setData] = useState<T>();
      const [error, setError] = useState<unknown>();
      const [loading, setLoading] = useState<boolean>(false);
    
      // 其余逻辑不变
      return { data, loading, error, status, statusText };
    };
    
    使用时可指定返回数据类型:
    interface User { id: number; name: string; }
    const { data } = useCustomFetch<User>('/api/user', {});
    

三、最后排查步骤

  • 重启开发服务器,清除缓存可能解决偶发性的配置异常
  • 检查项目webpack配置(非Create React App项目),确保React的resolve路径正确

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 17:36:31