React中useRef绑定Canvas报错:Cannot read properties of undefined (reading 'getContext')
解决useRef绑定canvas时
Cannot read properties of undefined (reading 'getContext')错误 问题根源
- 组件首次渲染阶段,canvas元素还未挂载到DOM树,此时
canvasRef.current的值为undefined,直接调用getContext必然抛出错误。 - 错误地将
width和height属性添加到了useRef返回的ref对象本身,而非真实的canvas DOM元素(即canvasRef.current)上。
解决方案
使用React的useEffect钩子,确保在DOM挂载完成后再操作canvas元素。useEffect的回调函数会在组件挂载完成后执行,此时canvasRef.current已指向真实的canvas节点。
修正后的完整代码
import { useRef, useEffect } from 'react'; function Landing() { const canvasRef = useRef(); const contextRef = useRef(); const frameCount = 230; const images = []; let ball = { frame: 0 }; // 预加载所有帧图片 const currentFrame = (index) => `../../assets/landing-animations/${(index + 1).toString()}.jpg`; for (let i = 0; i < frameCount; i++) { const img = new Image(); img.src = currentFrame(i); images.push(img); } useEffect(() => { // 确保canvas元素已挂载 if (!canvasRef.current) return; const canvas = canvasRef.current; const context = canvas.getContext("2d"); contextRef.current = context; // 设置并监听canvas尺寸 const setCanvasSize = () => { canvas.width = window.innerWidth; canvas.height = window.innerHeight; }; setCanvasSize(); window.addEventListener('resize', setCanvasSize); // 组件卸载时清理监听 return () => { window.removeEventListener('resize', setCanvasSize); }; }, []); function render() { // 提前判断避免空值报错 if (!contextRef.current || !canvasRef.current) return; const canvas = canvasRef.current; contextRef.current.clearRect(0, 0, canvas.width, canvas.height); contextRef.current.drawImage(images[ball.frame], 0, 0, canvas.width, canvas.height); } // 在此处添加GSAP滚动动画逻辑,示例: // gsap.to(ball, { // frame: frameCount - 1, // scrub: 1, // onUpdate: render // }) return ( <div className="landing"> <h1 className="landing__header">Welcome to my portfolio</h1> <canvas className="landing__canvas" ref={canvasRef}></canvas> </div> ); }
关键修正说明
useEffect的使用:空依赖数组[]确保代码只在组件挂载后执行一次,此时DOM已渲染完成,canvasRef.current有效。- canvas尺寸设置:将
width/height直接绑定到canvasRef.current(真实DOM元素),而非ref对象本身。 - 上下文缓存:用
contextRef存储canvas上下文,避免重复调用getContext。 - 空值检查:在
render函数中增加存在性判断,防止意外报错。 - 窗口resize监听:保证canvas尺寸随窗口变化自动更新(可选但实用)。
内容的提问来源于stack exchange,提问作者Omar
相关产品推荐
相关产品推荐

