React hook to manage a video.
Add the hook via the CLI:
npx @novajslabs/cli add useVideo
Or copy and paste the code into your project:
import { useEffect, useState, RefObject } from 'react'
export const useVideo = (ref: RefObject<HTMLVideoElement>) => {
const video = ref.current
const [videoState, setVideoState] = useState({
isPaused: video ? video?.paused : true,
isMuted: video ? video?.muted : false,
currentVolume: video ? video?.volume : 100,
currentTime: video ? video?.currentTime : 0,
})
const play = () => {
video?.play()
setVideoState((prev) => {
return {
...prev,
isPaused: false,
isMuted: video ? video.muted : prev.isMuted,
}
})
}
const pause = () => {
video?.pause()
setVideoState((prev) => {
return {
...prev,
isPaused: true,
}
})
}
const handlePlayPauseControl = (e: Event) => {
setVideoState((prev) => {
return {
...prev,
isPaused: (e.target as HTMLVideoElement).paused,
}
})
}
const togglePause = () => (video?.paused ? play() : pause())
const handleVolume = (delta: number) => {
const deltaDecimal = delta / 100
if (video) {
let newVolume = video?.volume + deltaDecimal
if (newVolume >= 1) {
newVolume = 1
} else if (newVolume <= 0) {
newVolume = 0
}
video.volume = newVolume
setVideoState((prev) => {
return {
...prev,
currentVolume: newVolume * 100,
}
})
}
}
const handleVolumeControl = (e: Event) => {
if (e.target && video) {
const newVolume = (e.target as HTMLVideoElement).volume * 100
if (newVolume === videoState.currentVolume) {
handleMute(video.muted)
return
}
setVideoState((prev) => ({
...prev,
currentVolume: (e.target as HTMLVideoElement).volume * 100,
}))
}
}
const handleMute = (mute: boolean) => {
if (video) {
video.muted = mute
setVideoState((prev) => {
return {
...prev,
isMuted: mute,
}
})
}
}
const handleTime = (delta: number = 5) => {
if (video) {
let newTime = video.currentTime + delta
if (newTime >= video.duration) {
newTime = video.duration
} else if (newTime <= 0) {
newTime = 0
}
video.currentTime = newTime
setVideoState((prev) => {
return {
...prev,
currentTime: newTime,
}
})
}
}
const handleTimeControl = (e: Event) => {
setVideoState((prev) => {
return {
...prev,
currentTime: (e.target as HTMLVideoElement).currentTime,
}
})
}
const toggleFullscreen = () => {
if (!document.fullscreenElement) {
video?.requestFullscreen().catch((err) => {
console.log(err)
})
} else {
document.exitFullscreen()
}
}
useEffect(() => {
return () => {
pause()
}
}, [])
useEffect(() => {
if (video) {
video.addEventListener('volumechange', handleVolumeControl)
video.addEventListener('play', handlePlayPauseControl)
video.addEventListener('pause', handlePlayPauseControl)
video.addEventListener('timeupdate', handleTimeControl)
return () => {
video.removeEventListener('volumechange', handleVolumeControl)
video.addEventListener('play', handlePlayPauseControl)
video.addEventListener('pause', handlePlayPauseControl)
video.addEventListener('timeupdate', handleTimeControl)
}
}
}, [video])
return {
...videoState,
play,
pause,
togglePause,
increaseVolume: (increase: number = 5) => handleVolume(increase),
decreaseVolume: (decrease: number = 5) => handleVolume(decrease * -1),
mute: () => handleMute(true),
unmute: () => handleMute(false),
toggleMute: () => handleMute(!video?.muted),
forward: (increase: number = 5) => handleTime(increase),
back: (decrease: number = 5) => handleTime(decrease * -1),
toggleFullscreen,
}
}
React 16.8 or higher
- Name
ref
- Type
- HTMLVideoElement
- Required
- required
- Description
The HTML video element to be manage.
- Name
isPaused
- Type
- boolean
- Description
Indicates whether the video is currently paused (true) or playing (false).
- Name
isMuted
- Type
- boolean
- Description
Indicates whether the video is currently muted (true) or unmuted (false).
- Name
currentVolume
- Type
- number
- Description
The current volume level of the video, ranging from 0 to 100.
- Name
currentTime
- Type
- number
- Description
The current playback position (in seconds) of the video.
- Name
play
- Type
- function
- Description
Play the video.
- Name
pause
- Type
- function
- Description
Pause the video.
- Name
togglePause
- Type
- function
- Description
Toggle between playing and pausing the video.
- Name
increaseVolume
- Type
- function
- Description
Increase the volume by a specified amount.
- Name
decreaseVolume
- Type
- function
- Description
Decrease the volume by a specified amount.
- Name
mute
- Type
- function
- Description
Mute the video.
- Name
unmute
- Type
- function
- Description
Unmute the video.
- Name
toggleMute
- Type
- function
- Description
Toggle between muting and unmuting the video.
- Name
forward
- Type
- function
- Description
Fast forward the video by a specified number of seconds.
- Name
back
- Type
- function
- Description
Rewind the video by a specified number of seconds.
- Name
toggleFullscreen
- Type
- function
- Description
Toggle fullscreen mode of the video.
import { useRef } from 'react'
import { useVideo } from './hooks/useVideo'
const App = () => {
const videoRef = useRef<HTMLVideoElement>(null)
const {
isPaused,
isMuted,
currentVolume,
currentTime,
play,
pause,
togglePause,
increaseVolume,
decreaseVolume,
mute,
unmute,
toggleMute,
forward,
back,
toggleFullscreen,
} = useVideo(videoRef)
return (
<div>
<video ref={videoRef} src="video.mp4" />
<div>
<button onClick={togglePause}>{isPaused ? 'Play' : 'Pause'}</button>
<button onClick={toggleMute}>{isMuted ? 'Unmute' : 'Mute'}</button>
<input
type="range"
min={0}
max={100}
value={currentVolume}
onChange={(e) => increaseVolume(Number(e.target.value))}
/>
<input
type="range"
min={0}
max={videoRef.current?.duration || 0}
value={currentTime}
onChange={(e) =>
videoRef.current &&
(videoRef.current.currentTime = Number(e.target.value))
}
/>
<button onClick={() => forward(10)}>Forward</button>
<button onClick={() => back(10)}>Back</button>
<button onClick={toggleFullscreen}>Fullscreen</button>
</div>
</div>
)
}
export default App
Here are some use cases where this React hook is useful:
- Implementing custom video controls
- Building a multimedia learning platform with interactive video playback controls
- Creating a video carousel component with autoplay functionality
- Developing a video editing tool with precise seeking and playback controls