Overview
The useEvent hook attaches an event listener to a VideoPlayer instance and automatically manages the subscription lifecycle. The listener is automatically removed when the component unmounts or when dependencies change.
Signature
function useEvent<T extends keyof AllPlayerEvents>(
player: VideoPlayer,
event: T,
callback: AllPlayerEvents[T]
): void
Parameters
The VideoPlayer instance to attach the event listener to
event
keyof AllPlayerEvents
required
The name of the event to listen for. Available events include:
onLoad - Video has loaded and is ready to play
onLoadStart - Video has started loading
onProgress - Playback progress update
onEnd - Video playback has ended
onError - An error occurred
onBuffer - Buffering state changed
onPlaybackStateChange - Playing/paused state changed
onPlaybackRateChange - Playback rate changed
onVolumeChange - Volume or muted state changed
onSeek - Seek operation occurred
onReadyToDisplay - Video frame is ready to display
onBandwidthUpdate - Network bandwidth changed
onTimedMetadata - Timed metadata received
onTextTrackDataChanged - Subtitle text data changed
onTrackChange - Selected text track changed
onAudioBecomingNoisy - Audio interrupted (Android)
onAudioFocusChange - Audio focus changed (Android)
onExternalPlaybackChange - AirPlay/external playback state changed (iOS)
onControlsVisibleChange - Video controls visibility changed
onStatusChange - Player status changed
The callback function to invoke when the event occurs. The function signature must match the event type.
Return Value
This hook does not return a value. It manages the event subscription internally.
Basic Usage
Simple Event Listener
import { useVideoPlayer, useEvent } from 'react-native-video';
function MyVideoPlayer() {
const player = useVideoPlayer('https://example.com/video.mp4');
useEvent(player, 'onEnd', () => {
console.log('Video ended!');
});
return <VideoView player={player} style={{ flex: 1 }} />;
}
With State Updates
import { useVideoPlayer, useEvent } from 'react-native-video';
import { useState } from 'react';
function MyVideoPlayer() {
const player = useVideoPlayer('https://example.com/video.mp4');
const [duration, setDuration] = useState(0);
const [currentTime, setCurrentTime] = useState(0);
const [isPlaying, setIsPlaying] = useState(false);
useEvent(player, 'onLoad', (data) => {
setDuration(data.duration);
});
useEvent(player, 'onProgress', (data) => {
setCurrentTime(data.currentTime);
});
useEvent(player, 'onPlaybackStateChange', (data) => {
setIsPlaying(data.isPlaying);
});
return (
<View>
<VideoView player={player} style={{ flex: 1 }} />
<Text>Status: {isPlaying ? 'Playing' : 'Paused'}</Text>
<Text>Progress: {currentTime.toFixed(1)}s / {duration.toFixed(1)}s</Text>
</View>
);
}
Error Handling
import { useVideoPlayer, useEvent } from 'react-native-video';
import { useState } from 'react';
function MyVideoPlayer() {
const player = useVideoPlayer('https://example.com/video.mp4');
const [error, setError] = useState<string | null>(null);
useEvent(player, 'onError', (error) => {
console.error('Video error:', error);
setError(error.message);
});
if (error) {
return <Text style={{ color: 'red' }}>Error: {error}</Text>;
}
return <VideoView player={player} style={{ flex: 1 }} />;
}
Advanced Usage
Multiple Event Listeners
import { useVideoPlayer, useEvent } from 'react-native-video';
import { useState } from 'react';
function MyVideoPlayer() {
const player = useVideoPlayer('https://example.com/video.mp4');
const [playbackInfo, setPlaybackInfo] = useState({
duration: 0,
currentTime: 0,
isPlaying: false,
isBuffering: false,
volume: 1.0,
muted: false,
});
useEvent(player, 'onLoad', (data) => {
setPlaybackInfo(prev => ({ ...prev, duration: data.duration }));
});
useEvent(player, 'onProgress', (data) => {
setPlaybackInfo(prev => ({ ...prev, currentTime: data.currentTime }));
});
useEvent(player, 'onPlaybackStateChange', (data) => {
setPlaybackInfo(prev => ({
...prev,
isPlaying: data.isPlaying,
isBuffering: data.isBuffering,
}));
});
useEvent(player, 'onVolumeChange', (data) => {
setPlaybackInfo(prev => ({
...prev,
volume: data.volume,
muted: data.muted,
}));
});
return (
<View>
<VideoView player={player} style={{ flex: 1 }} />
<Text>Duration: {playbackInfo.duration.toFixed(1)}s</Text>
<Text>Current Time: {playbackInfo.currentTime.toFixed(1)}s</Text>
<Text>Status: {playbackInfo.isPlaying ? 'Playing' : 'Paused'}</Text>
<Text>Buffering: {playbackInfo.isBuffering ? 'Yes' : 'No'}</Text>
<Text>Volume: {(playbackInfo.volume * 100).toFixed(0)}%</Text>
<Text>Muted: {playbackInfo.muted ? 'Yes' : 'No'}</Text>
</View>
);
}
Conditional Event Handling
import { useVideoPlayer, useEvent } from 'react-native-video';
import { useCallback, useState } from 'react';
function MyVideoPlayer({ enableAnalytics }: { enableAnalytics: boolean }) {
const player = useVideoPlayer('https://example.com/video.mp4');
const [watchTime, setWatchTime] = useState(0);
const handleProgress = useCallback((data) => {
setWatchTime(prev => prev + 0.1); // Assuming progress fires every 100ms
if (enableAnalytics) {
// Send analytics data
console.log('Analytics: Watch time', data.currentTime);
}
}, [enableAnalytics]);
useEvent(player, 'onProgress', handleProgress);
useEvent(player, 'onEnd', () => {
console.log(`Video completed. Total watch time: ${watchTime}s`);
});
return <VideoView player={player} style={{ flex: 1 }} />;
}
Subtitle Display
import { useVideoPlayer, useEvent } from 'react-native-video';
import { useState } from 'react';
function MyVideoPlayer() {
const player = useVideoPlayer({
uri: 'https://example.com/video.mp4',
externalSubtitles: [
{
uri: 'https://example.com/subtitles_en.vtt',
label: 'English',
type: 'vtt',
language: 'en',
},
],
});
const [subtitles, setSubtitles] = useState<string[]>([]);
useEvent(player, 'onTextTrackDataChanged', (texts) => {
setSubtitles(texts);
});
return (
<View>
<VideoView player={player} style={{ flex: 1 }} />
{subtitles.map((text, index) => (
<Text key={index} style={styles.subtitle}>
{text}
</Text>
))}
</View>
);
}
Network Bandwidth Monitoring
import { useVideoPlayer, useEvent } from 'react-native-video';
import { useState } from 'react';
function MyVideoPlayer() {
const player = useVideoPlayer('https://example.com/video.mp4');
const [bandwidth, setBandwidth] = useState({ bitrate: 0, width: 0, height: 0 });
useEvent(player, 'onBandwidthUpdate', (data) => {
setBandwidth({
bitrate: data.bitrate,
width: data.width || 0,
height: data.height || 0,
});
});
return (
<View>
<VideoView player={player} style={{ flex: 1 }} />
<Text>Bitrate: {(bandwidth.bitrate / 1000000).toFixed(2)} Mbps</Text>
<Text>Resolution: {bandwidth.width}x{bandwidth.height}</Text>
</View>
);
}
Event Types Reference
onLoad
(data: {
currentTime: number;
duration: number;
height: number;
width: number;
orientation: VideoOrientation;
}) => void
onLoadStart
(data: {
sourceType: 'local' | 'network';
source: VideoPlayerSource;
}) => void
onProgress
(data: {
currentTime: number;
bufferDuration: number;
}) => void
onPlaybackStateChange
(data: {
isPlaying: boolean;
isBuffering: boolean;
}) => void
onVolumeChange
(data: {
volume: number;
muted: boolean;
}) => void
onError
(error: VideoRuntimeError) => void
onBuffer
(buffering: boolean) => void
onEnd
onBandwidthUpdate
(data: {
bitrate: number;
width?: number;
height?: number;
}) => void
Notes
- The event listener is automatically removed when the component unmounts
- The listener is re-attached if
player, event, or callback changes
- For event listeners that don’t depend on React state/props, consider using the setup callback in
useVideoPlayer instead
- Event callbacks should be memoized with
useCallback when they depend on props or state to avoid unnecessary re-subscriptions
- The hook uses React’s
useEffect internally to manage the subscription lifecycle
When to Use
Use useEvent when:
- You need to update React state based on player events
- Your event callbacks depend on props or state
- You need to conditionally attach event listeners
- You’re adding listeners after the player is created
Use the setup callback in useVideoPlayer when:
- Your event listeners are static and don’t depend on state/props
- You want to configure the player during initialization
- Performance is critical (setup callback is more efficient)
See Also