Giả sử ta có component sau:
function VideoPlayer({ src, isPlaying }) {
return <video src={src} />
}
Component này sử dụng thẻ <video>
có sẵn trong trình duyệt và ta muốn truyền vào props isPlaying
từ parent component để kiểm soát khi nào thì video được phép phát:
import { useState } from 'react'
function App() {
const [isPlaying, setIsPlaying] = useState(false)
return (
<>
<button onClick={() => setIsPlaying(!isPlaying)}>
{isPlaying ? 'Pause' : 'Play'}
</button>
<VideoPlayer
isPlaying={isPlaying}
src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4"
/>
</>
)
}
Tuy nhiên, thẻ <video>
không có thuộc tính isPlaying
nên ta chỉ có thể gọi phương thức play()
hoặc pause()
thông qua DOM node của nó:
function VideoPlayer({ src, isPlaying }) {
const ref = useRef(null)
if (isPlaying) {
ref.current.play() // Calling these while rendering isn't allowed.
} else {
ref.current.pause() // Also, this crashes.
}
return <video ref={ref} src={src} loop playsInline />
}
Trong đoạn code trên, DOM node của thẻ <video>
được tham chiếu bởi một reference object bằng cách sử dụng hook useRef.
Tuy nhên, đoạn code ở trên không thể hoạt động. Lý do là vì khi chúng ta thực hiện truy cập đến thẻ <video>
trong quá trình render, nó vẫn chưa được tạo ra nên ta không thể gọi phương thức play()
hay pause()
.
Giải pháp cho vấn đề này là sử dụng useEffect để gọi hai phương thức cần gọi sau khi DOM node đã được tạo ra như sau:
function VideoPlayer({ src, isPlaying }) {
const ref = useRef(null)
useEffect(() => {
if (isPlaying) {
ref.current.play()
} else {
ref.current.pause()
}
})
return <video ref={ref} src={src} loop playsInline />
}
Related
list
from [[Wrapping the DOM Update in useEffect]]
sort file.ctime asc