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

无条件Hook调用组件出现Rendered more hooks错误排查求助

问题排查:React Hooks调用顺序错误(Rendered more hooks than during the previous render)

我编写了一个渲染文件上传可点击链接的React组件,代码如下:

import { gql, useLazyQuery, useMutation } from '@apollo/client';
import { useEffect, useState } from 'react';
import type FileUpload from '@app/data/models/FileUpload';
import { ExternalLink } from '@app/mcui/components/atoms/business-process/shared/ExternalLink';
import { isNonEmptyString } from '@divvy-homes/utils';

export type Props = {
  uploadId: FileUpload['id'];
};

const FILE_UPLOAD_QUERY = gql`
  query ($id: UUID!) {
    getFileUpload(id: $id) {
      id
      fileName
      url
    }
  }
`;

const SIGN_FILE_MUTATION = gql`
  mutation ($url: String!) {
    signAdminUploadUrl(url: $url)
  }
`;
export const FileUploadLink = ({ uploadId }: Props) => {
  const [fileUrl, setFileUrl] = useState<string>();
  const [fileName, setFileName] = useState<string>();
  const [getFileData] = useLazyQuery<{
    getFileUpload: {
      url: string;
      fileName: string;
    };
  }>(FILE_UPLOAD_QUERY, {
    onError: console.error,
    onCompleted: (data) => {
      setFileName(data.getFileUpload.fileName);
      setFileUrl(data.getFileUpload.url);
    },
    variables: {
      id: uploadId,
    },
  });

  useEffect(() => {
    void getFileData({ variables: { uploadId } });
  }, [getFileData, uploadId]);

  const [createSignedDocumentUrl] = useMutation<{ signAdminUploadUrl: string }>(
    SIGN_FILE_MUTATION,
    {
      onError: console.error,
      onCompleted: (urlData) => {
        const signedUrl = urlData.signAdminUploadUrl;
        window.open(signedUrl, '_blank', 'noreferrer');
      },
    },
  );

  return isNonEmptyString(fileUrl) ? (
    <ExternalLink
      onClick={() => void createSignedDocumentUrl({ variables: { url: fileUrl } })}
      text={fileName ?? ''}
    />
  ) : undefined;
};

每次使用该组件时,都会触发React错误:Rendered more hooks than during the previous render.,同时React提示父组件BusinessProcessDetails的Hook调用顺序发生变化,错误日志如下:

client.js:1 Warning: React has detected a change in the order of Hooks called by BusinessProcessDetails. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks

   Previous render            Next render
   ------------------------------------------------------
 1. useContext                 useContext
 2. useContext                 useContext
 3. useContext                 useContext
 4. useContext                 useContext
 5. useRef                     useRef
 6. undefined                  useState

当前使用React 18.2.0、TypeScript 4.9.5,检查上述组件代码未发现条件调用Hook的情况,寻求问题排查方案。


排查方案

  • 重点检查父组件BusinessProcessDetails的Hook调用:错误明确指向该父组件的Hook顺序变化,需排查父组件中是否存在以下情况:

    • 在if/else、switch等条件语句中调用Hook
    • 在循环、嵌套函数(比如事件处理函数、内部回调)中调用Hook
    • 动态渲染组件时,导致父组件自身的Hook调用数量/顺序随状态变化
  • 验证FileUploadLink的渲染时机:如果父组件中是通过条件判断(如{isUploaded && <FileUploadLink />})来渲染该组件,需确认这种条件渲染是否间接导致父组件的Hook调用逻辑异常。可尝试强制渲染该组件,观察错误是否消失。

  • 排查第三方组件的Hook使用:检查ExternalLink组件内部是否存在违反Hook规则的代码,比如在条件分支中调用Hook。可临时将ExternalLink替换为原生<a>标签测试,看错误是否复现。

  • 启用React Strict Mode:在开发环境开启Strict Mode,它会加倍渲染组件,能更精准地检测出Hook调用顺序的问题,帮助定位违规组件。

  • 检查组件树的深层子组件:问题可能出在BusinessProcessDetails下的任意子组件(非直接子组件),需逐层排查所有子组件的Hook调用是否符合规则,确保所有Hook都在组件顶层调用,无条件调用情况。

  • 确认Apollo Hooks的合规性:虽然当前组件的useLazyQuery和useMutation都是顶层调用,但需检查是否在它们的回调函数(如onCompleted、onError)中间接调用了Hook——不过从当前代码看不存在此问题,可作为兜底排查项。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 00:23:18