Detect an element has been resized by a user with React

I have a React component that renders a canvas and draws polygons on it:

function Plot(props) { const [localPlot, setLocalPlot] = useState(props.plot); ... useEffect(() => { // here we get the Canvas context and draw polygons to it }, [localPlot]); return ( <> <div style={{ resize: "both", border: "1px solid #32a1ce", overflow: "auto", }} ref={ref} > <canvas style={{ border: "thick solid #32a1ce" }} className="canvas" id={`canvas-${props.plotIndex}`} /> </div> );

Now I want to allow the user to be able to resize the canvas, so I've made that possible with the div around it and resize: "both". Im using the library react-resize-detector library to detect when the div has been resized:

function Plot(props) { const [localPlot, setLocalPlot] = useState(props.plot); ... useEffect(() => { // here we get the Canvas context and draw polygons to it }, [localPlot]); const onResize = useCallback((w, h) => { // on resize logic console.log("in onResize, w, h is ", w, h); }, []); const { width, height, ref } = useResizeDetector({ onResize, }); return ( <> <div style={{ resize: "both", border: "1px solid #32a1ce", overflow: "auto", }} ref={ref} > <canvas style={{ border: "thick solid #32a1ce" }} className="canvas" id={`canvas-${props.plotIndex}`} </div> );

The problem is that since I've added this, the canvas is blank. I believe this is because onResize is called after the render, and, somehow, wipes everything on the canvas. When I change to:

const { width, height, ref } = useResizeDetector({ handleHeight: false, refreshMode: 'debounce', refreshRate: 1000, onResize
});

I see the polygons on the canvas for a second, before they are wiped. What am I doing wrong?

1 Answer

You can use a combination of state and effect to repaint canvas when it is resized.

Here's a simplified example:

function Plot() { const onResize = useCallback((w, h) => { setSize({ w, h }); }, []); const canvasRef = useRef(); const { ref } = useResizeDetector({ onResize }); const [size, setSize] = useState({ w: 300, h: 300 }); useEffect(() => { const ctx = canvasRef.current.getContext("2d"); ctx.fillStyle = "green"; ctx.font = "18px serif"; ctx.fillText(`${size.w} x ${size.h}`, 10, 50); }, [size]); return ( <div ref={ref}> {/* subtract 10 for the resize corner in the enclosing div */} <canvas ref={canvasRef} width={size.w - 10} height={size.h - 10} /> </div> );
}

You can see a complete demo here:

Edit

0

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

You Might Also Like