React hook to manage an audio.
Add the hook via the CLI:
npx @novajslabs/cli add useAudio
Or copy and paste the code into your project:
import { useEffect, useState, RefObject } from 'react'
export const useAudio = (ref: RefObject<HTMLAudioElement>) => {
const audio = ref.current
const [audioState, setAudioState] = useState({
isPaused: audio ? audio?.paused : true,
isMuted: audio ? audio?.muted : false,
currentVolume: audio ? audio?.volume : 100,
currentTime: audio ? audio?.currentTime : 0,
})
const play = () => {
audio?.play()
setAudioState((prev) => {
return {
...prev,
isPaused: false,
isMuted: audio ? audio.muted : prev.isMuted,
}
})
}
const pause = () => {
audio?.pause()
setAudioState((prev) => {
return {
...prev,
isPaused: true,
}
})
}
const handlePlayPauseControl = (e: Event) => {
setAudioState((prev) => {
return {
...prev,
isPaused: (e.target as HTMLAudioElement).paused,
}
})
}
const togglePause = () => (audio?.paused ? play() : pause())
const handleVolume = (delta: number) => {
const deltaDecimal = delta / 100
if (audio) {
let newVolume = audio?.volume + deltaDecimal
if (newVolume >= 1) {
newVolume = 1
} else if (newVolume <= 0) {
newVolume = 0
}
audio.volume = newVolume
setAudioState((prev) => {
return {
...prev,
currentVolume: newVolume * 100,
}
})
}
}
const handleVolumeControl = (e: Event) => {
if (e.target && audio) {
const newVolume = (e.target as HTMLAudioElement).volume * 100
handleMute(audio.muted)
setAudioState((prev) => ({
...prev,
currentVolume: newVolume,
}))
}
}
const handleMute = (mute: boolean) => {
if (audio) {
audio.muted = mute
setAudioState((prev) => {
return {
...prev,
isMuted: mute,
}
})
}
}
const handleTime = (delta: number = 5) => {
if (audio) {
let newTime = audio.currentTime + delta
if (newTime >= audio.duration) {
newTime = audio.duration
} else if (newTime <= 0) {
newTime = 0
}
audio.currentTime = newTime
setAudioState((prev) => {
return {
...prev,
currentTime: newTime,
}
})
}
}
const handleTimeControl = (e: Event) => {
setAudioState((prev) => {
return {
...prev,
currentTime: (e.target as HTMLAudioElement).currentTime,
}
})
}
useEffect(() => {
return () => {
pause()
}
}, [])
useEffect(() => {
if (audio) {
audio.addEventListener('volumechange', handleVolumeControl)
audio.addEventListener('play', handlePlayPauseControl)
audio.addEventListener('pause', handlePlayPauseControl)
audio.addEventListener('timeupdate', handleTimeControl)
return () => {
audio.removeEventListener('volumechange', handleVolumeControl)
audio.addEventListener('play', handlePlayPauseControl)
audio.addEventListener('pause', handlePlayPauseControl)
audio.addEventListener('timeupdate', handleTimeControl)
}
}
}, [audio])
return {
...audioState,
play,
pause,
togglePause,
increaseVolume: (increase: number = 5) => handleVolume(increase),
decreaseVolume: (decrease: number = 5) => handleVolume(decrease * -1),
mute: () => handleMute(true),
unmute: () => handleMute(false),
toggleMute: () => handleMute(!audio?.muted),
forward: (increase: number = 5) => handleTime(increase),
back: (decrease: number = 5) => handleTime(decrease * -1),
}
}
React 16.8 or higher
- Name
ref
- Type
- HTMLAudioElement
- Required
- required
- Description
The HTML audio element to be manage.
- Name
isPaused
- Type
- boolean
- Description
Indicates whether the audio is currently paused (true) or playing (false).
- Name
isMuted
- Type
- boolean
- Description
Indicates whether the audio is currently muted (true) or unmuted (false).
- Name
currentVolume
- Type
- number
- Description
The current volume level of the audio, ranging from 0 to 100.
- Name
currentTime
- Type
- number
- Description
The current playback position (in seconds) of the audio.
- Name
play
- Type
- function
- Description
Play the audio.
- Name
pause
- Type
- function
- Description
Pause the audio.
- Name
togglePause
- Type
- function
- Description
Toggle between playing and pausing the audio.
- 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 audio.
- Name
unmute
- Type
- function
- Description
Unmute the audio.
- Name
toggleMute
- Type
- function
- Description
Toggle between muting and unmuting the audio.
- Name
forward
- Type
- function
- Description
Fast forward the audio by a specified number of seconds.
- Name
back
- Type
- function
- Description
Rewind the audio by a specified number of seconds.
import { useRef } from 'react'
import { useAudio } from './hooks/useAudio'
const App = () => {
const audioRef = useRef<HTMLAudioElement>(null)
const {
isPaused,
isMuted,
currentVolume,
currentTime,
play,
pause,
togglePause,
increaseVolume,
decreaseVolume,
mute,
unmute,
toggleMute,
forward,
back,
} = useAudio(audioRef)
return (
<div>
<audio ref={audioRef} src="audio.mp3" />
<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>
</div>
</div>
)
}
export default App
Here are some use cases where this React hook is useful:
- Controlling audio playback in a custom media player
- Implementing a podcast player with seek functionality
- Building a music streaming app with volume control
- Creating an audio preview component for an e-commerce site
- Developing an educational platform with audio lectures