import React, { useState } from 'react';
export default function App() {
const [video, setVideo] = useState();
const [currentTime, setCurrentTime] = useState(0);
return (
<div className="App">
{video && (
<video
controls
onTimeUpdate={(e) => setCurrentTime(e.target.currentTime)}
src={URL.createObjectURL(video)}
width="250"
/>
)}
<p>{currentTime}</p>
<input type="file" onChange={(e) => setVideo(e.target.files?.item(0))} />
</div>
);
}
一个很简单的 App,加载本地视频,在视频播放的同时,在页面上显示当前视频的时间。但是载入视频后,点击播放按钮,视频无法播放,看起来像是被重绘了,是因为 setCurrentTime
更新了状态数据,从而导致的重绘吗?那我能在哪里做 setCurrentTime 这个操作呢?谢谢鸭!
1
duduaba 2021-06-22 16:49:18 +08:00 1
拆分为视频、时间两个组件,然后用组件传值的形式更新 currentTime 组件,这样只有时间组件会更新了。或者简单点,用 ref 吧,或者再简单点,document.querySelector()的形式更新。
|
2
buddie OP @coderfuns 我将他们拆开了还是一样问题...
```jsx import React, { useState } from 'react'; function CurrentTime({ currentTime }) { return <p>{currentTime}</p>; } function Player({ video, onTimeUpdate }) { return ( <video controls onTimeUpdate={(e) => onTimeUpdate(e.target.currentTime)} src={URL.createObjectURL(video)} width="250" /> ); } export default function App() { const [video, setVideo] = useState(); const [currentTime, setCurrentTime] = useState(); return ( <> <input type="file" onChange={(e) => setVideo(e.target.files?.item(0))} /> {video && <Player video={video} onTimeUpdate={setCurrentTime} />} <CurrentTime currentTime={currentTime} /> </> ); } ``` |
3
buddie OP 好了!我把拆开的 Video 组建用 React.memo 包住就可以了!谢谢!
|
4
liyang5945 2021-06-22 17:05:36 +08:00 1
不能用 onTimeUpdate 这个事件,这个事件只要播放就会一直触发,就会一直重绘,给你个思路:监听 play 或 pause 事件,在监听方法里用定时器获取视频 refs 的当前播放时间
|
5
sweetcola 2021-06-22 17:15:34 +08:00 4
这个问题主要是 URL.createObjectURL(video) 这一段。
触发 re-render 后,React 会重新计算所有的值,包括 src={URL.createObjectURL(video)} 这一段。所以每当 re-render 后都会看上去停止了,实际上是因为 src 被重新计算了。 解法可以像你 3L 说的那样,也可以在不改动原来代码的基础上用 useMemo 。 ``` const objURL = useMemo(() => { return video ? URL.createObjectURL(video) : undefined }, [video]) ... src={objURL} ``` |
6
auroraccc 2021-06-22 17:25:29 +08:00 1
setCurrentTime 之后 App rerender 然后每次 createObjectURL 都会生成一个新的 URL 对象,然后 video 又 rerender 了
video 依赖的 src 应该挪到一个 useMemo 里面算出来 |