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

React集成fabric.js调用canvas.on报非函数错误如何解决

错误根源

报错Uncaught TypeError: canvas.on is not a function来自两个核心问题:

  1. 初始状态下canvas的值是空字符串''。React组件首次渲染时会先完整执行组件函数内的逻辑,之后才会运行useEffect中的副作用代码。你把canvas.on(...)写在组件函数顶层,执行到这行时fabric画布实例还没初始化,canvas只是个普通字符串,不存在on方法。
  2. fabric.Canvas实例是绑定了大量事件、持有复杂内部可变状态的对象,不适合存储在React state中——state更新会触发组件重渲染,很容易导致实例状态错乱、事件重复绑定的问题。同时把事件绑定写在组件顶层,每次组件重渲染都会重复执行绑定,后续会出现事件多次触发、内存泄漏的问题。
可运行的修正代码
import React, { useEffect, useRef } from 'react';
import { fabric } from "fabric";

function App() {
  // 用useRef存储fabric实例,实例变化不会触发组件重渲染
  const canvasRef = useRef(null);

  useEffect(() => {
    // 初始化画布实例
    const canvas = new fabric.Canvas('canvas', {
      height: 800,
      width: 800,
      backgroundColor: 'pink',
      selection: false,
      renderOnAddRemove: true,
    });
    canvasRef.current = canvas;

    // 实例初始化完成后再绑定事件
    const handleMouseOver = () => {
      console.log('hello');
    };
    canvas.on("mouse:over", handleMouseOver);

    // 组件卸载时清理资源
    return () => {
      canvas.off("mouse:over", handleMouseOver);
      canvas.dispose();
      canvasRef.current = null;
    };
  }, []);

  return (
    <div>
      <canvas id="canvas" />
    </div>
  );
}

export default App;
修正要点
  • 移除原有的canvas state,改用useRef存储fabric实例,避免不必要的重渲染
  • 事件绑定逻辑移动到useEffect内部,保证执行时画布实例已经完成初始化
  • 新增卸载清理逻辑:组件销毁时解绑事件、调用dispose方法回收画布资源,避免内存泄漏
  • 事件回调单独声明,保证解绑时可以精准移除对应监听,不会出现残留

内容的提问来源于stack exchange,提问作者Seweryn Woźniak

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 22:15:36