React集成fabric.js调用canvas.on报非函数错误如何解决
错误根源
报错Uncaught TypeError: canvas.on is not a function来自两个核心问题:
- 初始状态下
canvas的值是空字符串''。React组件首次渲染时会先完整执行组件函数内的逻辑,之后才会运行useEffect中的副作用代码。你把canvas.on(...)写在组件函数顶层,执行到这行时fabric画布实例还没初始化,canvas只是个普通字符串,不存在on方法。 - 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
相关产品推荐
相关产品推荐

