React+TS视频录制组件异常:录制结束后Video仍显示直播流
React+TS视频录制后Video仍显示直播流的原因及解决方法
核心原因解析
1. React DOM节点复用导致属性冲突
如果你的条件渲染是基于同一个<video>组件切换class和源,却没有给不同状态下的video设置唯一key,React的diff算法会认为这是同一个DOM元素,只会更新部分属性(比如class),而不会重建节点。此时原有的srcObject(直播流)仍绑定在video元素上,而浏览器的video元素规则是:srcObject优先级高于src属性,所以即使你设置了录制后的blob URL,依然会显示旧的直播流。
2. 未主动清理MediaStream引用
即使你切换了src属性,只要video元素的srcObject没有被显式置为null,它会一直保持对直播流的引用,浏览器会优先加载这个流,忽略你设置的src URL。
解决方法
方法一:强制React重建Video节点
给录制状态和录制完成状态的video分别设置不同的key,让React销毁旧节点并创建新节点:
{isRecording ? ( <video key="live-stream" className="LIVE" srcObject={mediaStream} autoPlay playsInline /> ) : ( <video key="recorded-video" className="RECORDED" src={recordingURL.current} autoPlay playsInline controls /> )}
方法二:手动清理直播流引用
如果不想重建DOM,可以通过ref获取video元素,在切换状态时先清空srcObject,再设置录制后的URL:
import { useRef, useEffect } from 'react'; // 组件内代码 const videoRef = useRef<HTMLVideoElement>(null); const [isRecording, setIsRecording] = useState(true); const recordingURL = useRef<string | null>(null); useEffect(() => { if (!isRecording && videoRef.current && recordingURL.current) { // 先清理直播流引用 videoRef.current.srcObject = null; // 再设置录制后的视频URL videoRef.current.src = recordingURL.current; } }, [isRecording]); // 渲染部分 <video ref={videoRef} className={isRecording ? "LIVE" : "RECORDED"} autoPlay playsInline controls={!isRecording} />
方法三:确保录制URL触发组件重渲染
如果你用useRef存储recordingURL,注意ref的变化不会触发React重渲染。如果录制URL的更新晚于isRecording的状态切换,建议将recordingURL存入useState,确保状态更新时组件能同步渲染最新的src:
const [recordingURL, setRecordingURL] = useState<string | null>(null); // 录制完成时更新state而非ref const handleRecordingStop = async () => { const blob = await recorder.stop(); const url = URL.createObjectURL(blob); setRecordingURL(url); setIsRecording(false); };
内容的提问来源于stack exchange,提问作者LeperAffinity666
相关产品推荐
相关产品推荐

