Using React and Typescript, I am trying to update a canvas based on a provided image with the canvas and file upload DOM elements separated into their own components.
The problem I'm facing is that when a new image is uploaded, the canvas does not update. I have been able to trick it in to updating by getting the page to re-render by doing something like saving a new change to one of the components, prompting my local server to update the page without refreshing.
interface ImageUploadProps { onChange: any }
const ImageUpload = (props: ImageUploadProps) => {
const [file, setFile] = useState();
const fileSelectedHandler = (event: any) => { props.onChange(URL.createObjectURL(event.target.files[0])); }
return (
<input type="file" name="image" id="uploaded-img" onChange={fileSelectedHandler}/>
);
}
export default ImageUpload;
interface CanvasProps { url: string, width: number, height: number }
const Canvas = (props: CanvasProps) => {
const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => {
if (!canvasRef.current){ throw new Error("Could get current canvas ref"); }
const canvas: HTMLCanvasElement = canvasRef.current;
const ctx: CanvasRenderingContext2D = canvas.getContext("2d")!;
let image: CanvasImageSource = new Image();
image.src = props.url;
ctx.drawImage(img, 0, 0, Number(canvas.width), Number(canvas.height));
}, [props.url]);
return (
<canvas ref={canvasRef} width={props.width} height={props.height}></canvas>
);
}
export default Canvas;
const App = () => {
const [url, setUrl] = useState("");
const handleURLChange = (u: string) => { setUrl(u); }
return (
<div>
<Canvas url={url} width={400} height={400}/>
<ImageUpload onChange={handleURLChange}/>
</div>
);
};
export default App;
I temporarily added an <img src={props.url}>
tag to the Canvas
to confirm that the component is being updated, which it is, since the image is being show on through that tag every time a new one is updated (as I would expect), while the canvas
element itself stays blank the whole time.
I also tried using useCallback()
in handleURLChange()
, and making the canvasRef
into a it's own useCanvas()
function like this. Neither change made any impact on the functionality.
I am still learning the ropes of React, so it is possible I am not using useEffect
or useRef
properly, but from my research they do seem to be correct.