React中img转iframe报错:Cannot read property addEventListener of null
我帮你梳理下代码里的几个关键问题,正是这些导致了报错和功能失效:
1. 事件监听器解绑参数缺失
在componentWillUnmount中,你移除点击事件时没有传入对应的处理函数,这会导致事件无法正确解绑,甚至可能引发内存泄漏。正确写法应该是:
componentWillUnmount() { const embedVideo = this.embedVideo.current; if (embedVideo) { embedVideo.removeEventListener("click", this.handleEmbedVideo); } }
2. DOM元素存在性判断错误
在handleEmbedVideo方法里,你用if (video_wrapper.length)判断元素是否存在,但video_wrapper是单个DOM节点(不是DOM集合),它没有length属性,这个判断永远不会成立,替换iframe的代码自然不会执行。应该改成直接判断元素本身是否存在:
handleEmbedVideo = () => { const video_wrapper = this.embedDiv.current; const embedUrl = video_wrapper?.getAttribute("data-yt-url"); // 正确判断元素是否存在 if (video_wrapper && embedUrl) { video_wrapper.innerHTML = '<iframe allowfullscreen frameborder="0" class="embed-responsive-item" src="' + embedUrl + '"></iframe>'; } };
这里还添加了可选链?.,避免video_wrapper为null时调用getAttribute抛出额外错误。
3. 子组件中video变量未定义
在函数组件ViewOneCourse里,<img src={video.poster} />中的video变量没有声明或从props传入,这会直接导致渲染错误——组件渲染失败的话,DOM元素不会生成,ref自然会是null,这也是你看到Cannot read property addEventListener of null报错的核心原因之一。
你需要先给子组件传入video参数:
export const ViewOneCourse = ({ embedDiv, embedVideo, video }) => { return ( <div> <Grid item lg={5} md={5}> <div className="course-brick"> <div className="youtube-video-place embed-responsive embed-responsive-4by3 " data-yt-url="https://www.youtube.com/embed/BjngNWP9C5s?rel=0&showinfo=0&autoplay=1" ref={embedDiv} > <img src={video.poster} async className="play-youtube-video" ref={embedVideo} ></img> </div> </div> </Grid> </div> ) }
然后在父组件渲染时传入video数据(假设你从props或state中获取到了视频信息):
render() { const { video } = this.props; // 或从state中读取 return ( <ViewOneCourse embedDiv={this.embedDiv} embedVideo={this.embedVideo} video={video} /> ); }
补充:ref绑定的规范建议
虽然你通过props传递ref给子组件的方式是可行的,但更规范的做法是用React.forwardRef包装函数组件。不过只要修复了前面的问题,当前写法的ref也能正常获取到DOM元素。如果还是出现ref为null的情况,可以检查子组件是否存在条件渲染导致元素未渲染的情况。
把这些问题都修复后,点击图片应该就能正常替换成iframe播放视频了。
内容的提问来源于stack exchange,提问作者freetyy

