我一直在 React 中使用视频元素。通过使用 ref 来设置 srcObject
,它可以正常工作。但是,一旦应用程序重新呈现,视频就会丢失并变黑。
无论如何允许视频通过状态更新(重新渲染)继续播放?
以下代码的行为:
getMedia
什么都不做。getMedia
正确呈现视频元素中的相机源。startCall
会终止视频源(变黑)。export const CallTestingPage: FunctionComponent = () => {
const classes = useStyles();
const localVideoElement = useRef<HTMLVideoElement>(null);
const remoteVideoElement = useRef<HTMLVideoElement>(null);
const [startCallBtnDisabled, setStartCallBtnDisabled] = useState(true);
async function getMedia() {
// console.log("getMedia");
try {
const cameraStream = await navigator.mediaDevices.getUserMedia({video: true});
localVideoElement!.current!.srcObject = cameraStream;
console.log(localVideoElement.current?.srcObject);
setStartCallBtnDisabled(false);
} catch (e) {
const message = `getUserMedia error: ${e.name} :: PermissionDeniedError may mean invalid constraints.`;
alert(message);
}
}
function startCall() {
setStartCallBtnDisabled(true);
}
function endCall() {}
function LocalVideo () {
const classes = useStyles();
return (
<>
<div id="localVideo">
<div>LOCAL VIDEO</div>
<br />
<video autoPlay muted className={classes.videoPlayer} ref={localVideoElement} />
</div>
</>
)
}
function RemoteVideo () {
const classes = useStyles();
return (
<>
<div id="remoteVideo">
<div>REMOTE VIDEO</div>
<br />
<video autoPlay muted className={classes.videoPlayer} ref={remoteVideoElement} />
</div>
</>
)
}
return (
<PageSection>
<div className={classes.root}>
<Grid container spacing={3}>
<Grid item xs={12} sm={5}>
<Paper className={classes.paper}>
<LocalVideo />
</Paper>
</Grid>
<Grid item xs={12} sm={2}>
<Paper className={classes.paper}>
ACTIVE CANDIDATES
<br />
<br />
LOCAL
<br />
<br />
REMOTE
<br />
</Paper>
</Grid>
<Grid item xs={12} sm={5}>
<Paper className={classes.paper}>
<RemoteVideo />
</Paper>
</Grid>
<Grid item xs={12}>
<Paper className={classes.paper}>
<ButtonGroup color="primary" aria-label="outlined primary button group">
<Button onClick={getMedia}>Get Media</Button>
<Button onClick={startCall} disabled={startCallBtnDisabled}>Start Call</Button>
<Button onClick={endCall}>Hang Up</Button>
</ButtonGroup>
</Paper>
</Grid>
<Grid item xs={12}>
<Paper className={classes.paper}>
STATS
<br />
<br />
<br />
{/* <div ref={stats}></div> */}
</Paper>
</Grid>
</Grid>
</div>
</PageSection>
);
}
编辑:
useEffect(() => {
console.log(localVideoElement.current?.srcObject)
}, [startCallBtnDisabled])
// this returns null every time
答案 0 :(得分:1)
我很确定问题在于您已经在另一个功能组件内部定义了功能组件。这通常是不好的做法,但在您的情况下尤其成问题,因为这意味着,每次顶级功能组件重新渲染时,这些组件都会被全新的组件定义替换,这意味着 React 不知道它可以重新-使用现有的 <video>
元素。试试这个:
export const CallTestingPage: FunctionComponent = () => {
const classes = useStyles();
const localVideoElement = useRef<HTMLVideoElement>(null);
const remoteVideoElement = useRef<HTMLVideoElement>(null);
const [startCallBtnDisabled, setStartCallBtnDisabled] = useState(true);
async function getMedia() {
// console.log("getMedia");
try {
const cameraStream = await navigator.mediaDevices.getUserMedia({video: true});
localVideoElement!.current!.srcObject = cameraStream;
console.log(localVideoElement.current?.srcObject);
setStartCallBtnDisabled(false);
} catch (e) {
const message = `getUserMedia error: ${e.name} :: PermissionDeniedError may mean invalid constraints.`;
alert(message);
}
}
function startCall() {
setStartCallBtnDisabled(true);
}
function endCall() {}
return (
<PageSection>
<div className={classes.root}>
<Grid container spacing={3}>
<Grid item xs={12} sm={5}>
<Paper className={classes.paper}>
<LocalVideo localVideoElement={localVideoElement} />
</Paper>
</Grid>
<Grid item xs={12} sm={2}>
<Paper className={classes.paper}>
ACTIVE CANDIDATES
<br />
<br />
LOCAL
<br />
<br />
REMOTE
<br />
</Paper>
</Grid>
<Grid item xs={12} sm={5}>
<Paper className={classes.paper}>
<RemoteVideo remoteVideoElement={remoteVideoElement} />
</Paper>
</Grid>
<Grid item xs={12}>
<Paper className={classes.paper}>
<ButtonGroup color="primary" aria-label="outlined primary button group">
<Button onClick={getMedia}>Get Media</Button>
<Button onClick={startCall} disabled={startCallBtnDisabled}>Start Call</Button>
<Button onClick={endCall}>Hang Up</Button>
</ButtonGroup>
</Paper>
</Grid>
<Grid item xs={12}>
<Paper className={classes.paper}>
STATS
<br />
<br />
<br />
{/* <div ref={stats}></div> */}
</Paper>
</Grid>
</Grid>
</div>
</PageSection>
);
}
function LocalVideo ({localVideoElement}) {
const classes = useStyles();
return (
<>
<div id="localVideo">
<div>LOCAL VIDEO</div>
<br />
<video autoPlay muted className={classes.videoPlayer} ref={localVideoElement} />
</div>
</>
)
}
function RemoteVideo ({remoteVideoElement}) {
const classes = useStyles();
return (
<>
<div id="remoteVideo">
<div>REMOTE VIDEO</div>
<br />
<video autoPlay muted className={classes.videoPlayer} ref={remoteVideoElement} />
</div>
</>
)
}