Open subtext916 opened 3 months ago
To give an example of what I am trying to do: A simplified example of my hook:
const useCanvas = ({ className = 'canvas' }) => {
const [initialized, setInitialized] = useState(false)
const { selectedObjects, editor, onReady: onReadyOriginal } = useFabricJSEditor()
const getCanvasObjects = useCallback(() => {
return editor?.canvas?.getObjects()
}, [editor])
useEffect(() => {
if (editor?.canvas && !initialized) setInitialized(true)
}, [initialized, editor, onReady])
const Canvas = useMemo(() => {
return () => <FabricJSCanvas className={className} onReady={onReady} />;
}, [className, onReady]);
return {
Canvas,
ready: initialized,
getCanvasObjects
}
}
export default useCanvas
@subtext916 hi can you please share code when is failing on clearRect
Exact details... React project with the following files: tsconfig.json
index.tsx:
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
const root = ReactDOM.createRoot(
document.getElementById("root") as HTMLElement
);
root.render(
<App />
);
App.tsx:
import React from 'react'
import useCanvas from './useCanvas'
function App() {
const { Canvas } = useCanvas({
className: 'canvas'
})
return (
<div className="App">
<Canvas />
</div>
)
}
export default App
useCanvas.tsx:
import React, { useEffect, useMemo, useCallback, useState, useRef } from 'react'
import { FabricJSCanvas, useFabricJSEditor } from 'fabricjs-react'
import { fabric } from 'fabric'
interface CanvasProps {
className?: string
}
const useCanvas = ({ className = 'canvas' }: CanvasProps) => {
const editorRef = useRef<any>(null)
const [initialized, setInitialized] = useState(false)
const { editor, onReady: onReadyOriginal } = useFabricJSEditor()
const onReady = useCallback(onReadyOriginal, []) // eslint-disable-line react-hooks/exhaustive-deps
useEffect(() => {
if (editor?.canvas) {
if (!initialized) {
setInitialized(true)
editorRef.current = editor
}
}
}, [initialized, editor, onReady])
/**
* Main canvas component
*/
const Canvas = useMemo(() => {
return () => <FabricJSCanvas className={className} onReady={onReady} />;
}, [className, onReady]);
useEffect(() => {
return () => {
editorRef.current?.canvas.off()
editorRef.current?.canvas.clear()
editorRef.current?.canvas.dispose()
fabric.util.requestAnimFrame(() => {})
}
}, [])
return {
Canvas,
ready: initialized
}
}
export default useCanvas
Now, run react project... npm run start
Modify App.tsx or index.tsx, it crashes with the clearRect error.
Am I doing something wrong? Thank you for looking at this
Also, could it be related to this topic? https://github.com/fabricjs/fabric.js/issues/8299 (scroll down to the "React Compatibility" section)
Oh, one other detail. I am using: "fabric": "^5.3.0", "fabricjs-react": "^1.2.2",
not sure, can you prepare a codesanbox runtime, I think based on the sample code, there is no benefit for now to separate hook from canvas component, all together can be inside Canvas component (don't think returning component from hook looks like a good pattern)
Hello, I have been exploring this solution and wanted to wrap it in my own hook to eliminate the "fabricjs" specific stuff and create a more generic "useCanvas" hook which returns a Canvas (instance of the FabricJSCanvas) and some methods to work with it, which all use the "editor" returned from the fabricjs-react hook. I am finding that this approach does not work because if I make a change to my App.tsx parent component, which triggers a re-render (hot deploy), the whole thing crashes with the error: TypeError: Cannot read properties of null (reading 'clearRect')
I have tried adding a useEffect return function to call editor.canvas.dispose() editor.canvas.off() editor.canvas.clear() and I cannot find a way around this problem. Is this a problem? Am I using this hook wrong? Any advice would be appreciated.