React, insert/append/render existing <HTMLCanvasElement>

Viewed 518

In my <App> Context, I have a canvas element (#offScreen) that is already hooked in the requestAnimationFrame loop and appropriately drawing to that canvas, verified by .captureStream to a <video> element.

In my <Canvas> react component, I have the following code (which works, but seems clunky/not the best way to copy an offscreen canvas to the DOM):

NOTE: master is the data object for the <App> Context.

function Canvas({ master, ...rest } = {}) {
    const canvasRef = useRef(master.canvas);
    
    const draw = ctx => {
        ctx.drawImage(master.canvas, 0, 0);
    };
    useEffect(() => {
        const canvas = canvasRef.current;
        const ctx = canvas.getContext("2d");
        let animationFrameId;

        const render = () => {
            draw(ctx)
            animationFrameId = window.requestAnimationFrame(render)
        }
        render();
        
        return () => {
            window.cancelAnimationFrame(animationFrameId);
        }
    }, [ draw ]);

    return (
        <canvas
            ref={ canvasRef }
            onMouseDown={ e => console.log(master, e) }
        />
    );
};

Edited for clarity based on comments

In my attempts to render the master.canvas directly (e.g. return master.canvas; in <Canvas>), I get some variation of the error "Objects cannot be React children" or I get [object HTMLCanvasElement] verbatim on the screen.

It feels redundant to take the #offScreen canvas and repaint it each frame. Is there, instead, a way to insert or append #offScreen into <Canvas>, so that react is just directly utilizing #offScreen without having to repaint it into the react component canvas via the ref?

Specific Issue: Functionally, I'm rendering a canvas twice--once off screen and once in the react component. How do I (replace/append?) the component's <canvas> element with the offscreen canvas (#offScreen), instead of repainting it like I'm doing now?

1 Answers

For anyone interested, this was actually fairly straightforward, as I overcomplicated it substantially.

export function Canvas({ canvas, ...rest }) {
    const container = useRef(null);

    useEffect(() => {
        container.current.innerHTML = "";
        container.current.append(canvas);
    }, [ container, canvas ]);

    return (
        <div ref={ container } />
    )
}
Related