无条件Hook调用组件出现Rendered more hooks错误排查求助
我编写了一个渲染文件上传可点击链接的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

