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

ESLint报‘Cannot access refs during render’但未访问ref的问题排查

ESLint报错“Cannot access refs during render”:传递dialog.ref给自定义组件时触发,但解构写法正常

问题描述

我在将ref传递给自定义Dialog组件时,使用dialog.ref的写法会触发eslint-plugin-react-hooks的react-hooks/refs规则报错,提示“Cannot access refs during render”。但我并没有访问ref.current,只是传递ref对象本身。奇怪的是,用解构const { ref } = useDialog()的写法就能正常工作。我更偏好dialog.ref这种写法,因为需要处理多个对话框实例(比如dialogA.ref、dialogB.ref)。

错误提示:

Error: Cannot access refs during render
React refs are values that are not needed for rendering. Refs should only be accessed outside of render, such as in event handlers or effects. Accessing a ref value (the current property) during render can cause your component not to update as expected

相关代码

自定义Dialog组件

export type DialogProps = ComponentPropsWithRef<"dialog">;

export function Dialog({ className = "", ...props }: DialogProps) {
  return (
    <dialog
      className={`ui-dialog ${className}`}
      {...props}
    />
  );
}

useDialog Hook

export type UseDialogReturnType = {
  ref: RefObject<HTMLDialogElement | null>;
  isOpen: boolean;
  handleOpen: () => void;
  handleClose: () => void;
};

export function useDialog(): UseDialogReturnType {
  const ref = useRef<HTMLDialogElement>(null);
  const [isOpen, setIsOpen] = useState<boolean>(false);

  const handleOpen = () => {
    if (ref.current) {
      ref.current.showModal();
      setIsOpen(true);
    }
  };

  const handleClose = () => {
    if (ref.current) {
      ref.current.close();
      setIsOpen(false);
    }
  };

  return {
    ref,
    isOpen,
    handleOpen,
    handleClose,
  };
}

使用组件的代码

export function MyComponent() {
  const dialog = useDialog();
  const { ref } = useDialog();

  return (
    <>
      <Dialog ref={dialog.ref} /> {/* Error: Cannot access refs during render */}
      <Dialog ref={ref} />        {/* 正常工作 */}
    </>
  )
}

原因分析

这是ESLint react-hooks/refs规则的误判。该规则的设计目的是防止在渲染阶段访问ref.current,但它的静态检测逻辑会误将“从Hook返回的对象中访问ref属性”的行为判定为违规。而解构写法直接获取ref变量,规则能正确识别这是传递ref对象本身,而非访问current属性,因此不会报错。

解决方法

方法1:局部禁用ESLint规则

在报错的行添加注释,临时禁用该规则:

export function MyComponent() {
  const dialog = useDialog();

  return (
    <>
      {/* eslint-disable-next-line react-hooks/refs */}
      <Dialog ref={dialog.ref} />
    </>
  )
}

这种方法简单直接,适合只需要在个别地方处理的场景。

方法2:将ref提取为单独变量

把dialog.ref赋值给一个独立变量,再传递给组件,绕开ESLint的误判:

export function MyComponent() {
  const dialog = useDialog();
  const dialogRef = dialog.ref; // 提取为单独变量

  return (
    <>
      <Dialog ref={dialogRef} />
    </>
  )
}

这种写法既保留了dialog对象的多实例管理方式,又能避免ESLint报错。

方法3:调整ESLint规则配置(全局)

如果项目中经常需要这种写法,可以修改ESLint配置文件(如.eslintrc.js),调整react-hooks/refs规则的选项,允许从Hook返回的对象中访问ref属性:

module.exports = {
  // ...其他配置
  rules: {
    "react-hooks/refs": ["error", { allowDestructuring: true }]
  }
};

注意:该选项需要确保你的ESLint插件版本支持(需eslint-plugin-react-hooks@4.6.0及以上)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.01 13:28:09