React中URL.createObjectURL二次上传文件时无法生成对象URL问题
根因分析
- HTML规范中
<source>标签的src属性变更不会触发父级<video>元素的资源重载行为,浏览器会沿用首次加载的视频资源,导致预览不刷新。 - 直接在JSX中调用
URL.createObjectURL会在每次组件重渲染时重复生成对象URL,且未释放旧的URL会造成内存泄漏,也可能引发资源标识冲突。
修复方案
import { useState, useEffect } from 'react' const VideoUpload = () => { const [videoFile, setVideoFile] = useState<File>() const [videoPreviewUrl, setVideoPreviewUrl] = useState<string>('') useEffect(() => { // 销毁上一个旧的对象URL,释放内存 if (videoPreviewUrl) { URL.revokeObjectURL(videoPreviewUrl) } // 新文件存在时生成新的预览URL if (videoFile) { setVideoPreviewUrl(URL.createObjectURL(videoFile)) } // 组件卸载时销毁最后生成的对象URL return () => { if (videoPreviewUrl) { URL.revokeObjectURL(videoPreviewUrl) } } }, [videoFile]) const uploadVideo = (selectorFiles: FileList | null) => { if(selectorFiles?.length) { setVideoFile(selectorFiles[0]) } } return ( <> {/* 直接将预览地址绑定到video的src属性,变更时会自动触发资源重载 */} <video controls src={videoPreviewUrl} style={{maxWidth: '600px'}} /> <br /> <input type="file" accept="video/*" onChange={(e) => uploadVideo(e.target.files)} /> </> ) }
可选兼容方案
如果必须保留<source>标签写法,给<video>标签绑定与当前文件关联的唯一key值即可,文件更新时key变化会触发整个video组件重新渲染,自动加载新资源:
<video controls key={videoFile ? `${videoFile.name}-${videoFile.lastModified}` : 'empty'}> <source src={videoPreviewUrl} /> </video>
内容的提问来源于stack exchange,提问作者k10a
相关产品推荐
相关产品推荐

