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

React中useRef语法疑问:Canvas元素引用代码报错求解

问题分析与修复

你的代码里有几个关键问题,直接导致useRef无法正常工作,还会引发额外的逻辑错误,下面一步步拆解修复:

1. 修正TypeScript泛型语法错误

你写的useRef和useState语法完全不符合TypeScript规范,这是最核心的问题:
错误写法:

const canvasRef = (useRef < HTMLCanvasElement) | (null > null);
const [context, setContext] = (useState < CanvasRenderingContext2D) | (null > null);

正确的泛型写法是把联合类型放在尖括号内,初始化值放在函数的圆括号里:

const canvasRef = useRef<HTMLCanvasElement | null>(null);
const [context, setContext] = useState<CanvasRenderingContext2D | null>(null);

2. 修复useEffect无限循环问题

你原来的useEffect依赖了context,但内部又调用setContext修改它,这会触发无限循环——每次context更新都会重新执行useEffect,然后再次更新context,往复不停。

而且完全没必要把canvas上下文存在state里,上下文和canvas元素绑定,直接从ref获取或者用另一个ref存储即可,避免不必要的组件重渲染。

3. 完整修正后的代码

export interface ICanvasBoard {
  height: number;
  width: number;
}

const CanvasBoard = ({ height, width }: ICanvasBoard) => {
  const canvasRef = useRef<HTMLCanvasElement | null>(null);
  // 用ref存上下文,避免state更新触发无意义重渲染
  const contextRef = useRef<CanvasRenderingContext2D | null>(null);

  useEffect(() => {
    if (!canvasRef.current) return;
    
    // 获取并存储canvas上下文
    const ctx = canvasRef.current.getContext("2d");
    contextRef.current = ctx;

    // 示例绘制逻辑,可根据需求修改
    if (ctx) {
      ctx.clearRect(0, 0, width, height);
      ctx.fillStyle = "#ff4444";
      ctx.fillRect(20, 20, 80, 80);
    }
  }, [height, width]); // 画布尺寸变化时重新执行绘制逻辑

  return (
    <canvas
      ref={canvasRef}   
      style={{
        border: "3px solid black",
      }}
      height={height}
      width={width}
    />
  );
};

关键知识点说明

  • useRef<HTMLCanvasElement | null>(null):声明一个可存储Canvas元素或null的ref,初始值为null(组件挂载前ref.current默认是null)。
  • 用ref存上下文而非state:上下文不会频繁变化,用state会触发组件重渲染,ref更新则不会,更高效。
  • useEffect依赖height和width:当画布尺寸变化时,重新获取上下文并绘制,避免内容错位。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 17:52:37