React Native Video provides two essential hooks for managing video playback in your React components.
useVideoPlayer
Creates and manages a VideoPlayer instance with automatic lifecycle handling.
Signature
useVideoPlayer(
source: VideoConfig | VideoSource | VideoPlayerSource,
setup?: (player: VideoPlayer) => void
): VideoPlayer
Parameters
-
source: The video source to play. Can be:
VideoSource - Simple object with URI: { uri: 'https://example.com/video.mp4' }
VideoConfig - Full configuration with source and options
VideoPlayerSource - Native source object
-
setup (optional): Callback function to configure the player. Called when the player starts loading the source.
Return Value
Returns a VideoPlayer instance that persists across re-renders.
Behavior
The hook manages the player lifecycle:
- Creates a new player when the component mounts
- Recreates the player if the source changes
- Automatically cleans up the player when the component unmounts
If initializeOnCreation is true (default), the setup function is called when the player starts loading. If false, it’s called immediately when the player is created.
Basic Usage
import { useVideoPlayer, VideoView } from 'react-native-video';
function MyVideo() {
const player = useVideoPlayer(
{ uri: 'https://example.com/video.mp4' }
);
return (
<VideoView
player={player}
style={{ width: '100%', height: 300 }}
/>
);
}
With Setup Callback
Use the setup callback to configure the player when it loads:
import { useVideoPlayer, VideoView } from 'react-native-video';
function MyVideo() {
const player = useVideoPlayer(
{ uri: 'https://example.com/video.mp4' },
(player) => {
// Configure player when it starts loading
player.volume = 0.5;
player.loop = true;
player.playInBackground = true;
}
);
return (
<VideoView
player={player}
style={{ width: '100%', height: 300 }}
/>
);
}
With VideoConfig
Pass a full configuration object for advanced options:
import { useVideoPlayer, VideoView } from 'react-native-video';
import type { VideoConfig } from 'react-native-video';
function MyVideo() {
const config: VideoConfig = {
uri: 'https://example.com/video.mp4',
externalSubtitles: [
{
uri: 'https://example.com/subtitles_en.vtt',
label: 'English',
language: 'en',
type: 'vtt'
}
],
initializeOnCreation: true
};
const player = useVideoPlayer(config, (player) => {
player.volume = 0.8;
});
return (
<VideoView
player={player}
style={{ width: '100%', height: 300 }}
/>
);
}
Controlling Playback
Access the player instance to control playback:
import { useVideoPlayer, VideoView } from 'react-native-video';
import { Button, View } from 'react-native';
function VideoControls() {
const player = useVideoPlayer(
{ uri: 'https://example.com/video.mp4' }
);
return (
<View>
<VideoView
player={player}
style={{ width: '100%', height: 300 }}
/>
<View style={{ flexDirection: 'row', justifyContent: 'center' }}>
<Button
title={player.isPlaying ? 'Pause' : 'Play'}
onPress={() => player.isPlaying ? player.pause() : player.play()}
/>
<Button
title="Restart"
onPress={() => player.seekTo(0)}
/>
</View>
</View>
);
}
Dynamic Source Changes
Change the video source dynamically:
import { useVideoPlayer, VideoView } from 'react-native-video';
import { Button, View } from 'react-native';
import { useState } from 'react';
function VideoSwitcher() {
const [videoIndex, setVideoIndex] = useState(0);
const videos = [
'https://example.com/video1.mp4',
'https://example.com/video2.mp4',
'https://example.com/video3.mp4'
];
const player = useVideoPlayer(
{ uri: videos[videoIndex] }
);
return (
<View>
<VideoView
player={player}
style={{ width: '100%', height: 300 }}
/>
<Button
title="Next Video"
onPress={() => setVideoIndex((videoIndex + 1) % videos.length)}
/>
</View>
);
}
When the source changes, the hook creates a new player instance and cleans up the old one. This may cause a brief interruption in playback.
useEvent
Attaches an event listener to a VideoPlayer instance for a specified event.
Signature
useEvent<T extends keyof AllPlayerEvents>(
player: VideoPlayer,
event: T,
callback: AllPlayerEvents[T]
): void
Parameters
- player: The
VideoPlayer instance to attach the event to
- event: The name of the event to listen for
- callback: The callback function to invoke when the event occurs
Behavior
The hook automatically:
- Adds the event listener when the component mounts or dependencies change
- Removes the event listener when the component unmounts or dependencies change
- Ensures the listener is always up-to-date with the latest callback
Basic Usage
import { useVideoPlayer, VideoView, useEvent } from 'react-native-video';
function MyVideo() {
const player = useVideoPlayer(
{ uri: 'https://example.com/video.mp4' }
);
useEvent(player, 'onLoad', (data) => {
console.log('Video loaded, duration:', data.duration);
});
useEvent(player, 'onEnd', () => {
console.log('Video ended');
});
return (
<VideoView
player={player}
style={{ width: '100%', height: 300 }}
/>
);
}
Progress Tracking
Track playback progress:
import { useVideoPlayer, VideoView, useEvent } from 'react-native-video';
import type { onProgressData } from 'react-native-video';
import { Text, View } from 'react-native';
import { useState } from 'react';
function VideoWithProgress() {
const [currentTime, setCurrentTime] = useState(0);
const [duration, setDuration] = useState(0);
const player = useVideoPlayer(
{ uri: 'https://example.com/video.mp4' }
);
useEvent(player, 'onProgress', (data: onProgressData) => {
setCurrentTime(data.currentTime);
});
useEvent(player, 'onLoad', (data) => {
setDuration(data.duration);
});
return (
<View>
<VideoView
player={player}
style={{ width: '100%', height: 300 }}
/>
<Text>
{Math.floor(currentTime)}s / {Math.floor(duration)}s
</Text>
</View>
);
}
Status Changes
Monitor player status:
import { useVideoPlayer, VideoView, useEvent } from 'react-native-video';
import type { VideoPlayerStatus } from 'react-native-video';
import { Text, View } from 'react-native';
import { useState } from 'react';
function VideoStatus() {
const [status, setStatus] = useState<VideoPlayerStatus>('idle');
const player = useVideoPlayer(
{ uri: 'https://example.com/video.mp4' }
);
useEvent(player, 'onStatusChange', (newStatus) => {
setStatus(newStatus);
console.log('Status changed to:', newStatus);
});
return (
<View>
<VideoView
player={player}
style={{ width: '100%', height: 300 }}
/>
<Text>Status: {status}</Text>
</View>
);
}
Error Handling
Handle playback errors:
import { useVideoPlayer, VideoView, useEvent } from 'react-native-video';
import type { VideoRuntimeError } from 'react-native-video';
import { Alert } from 'react-native';
function VideoWithErrorHandling() {
const player = useVideoPlayer(
{ uri: 'https://example.com/video.mp4' }
);
useEvent(player, 'onError', (error: VideoRuntimeError) => {
console.error('Video error:', error);
Alert.alert(
'Playback Error',
`${error.code}: ${error.message}`
);
});
return (
<VideoView
player={player}
style={{ width: '100%', height: 300 }}
/>
);
}
Multiple Events
Listen to multiple events:
import { useVideoPlayer, VideoView, useEvent } from 'react-native-video';
import { useState } from 'react';
function VideoEventLogger() {
const [events, setEvents] = useState<string[]>([]);
const player = useVideoPlayer(
{ uri: 'https://example.com/video.mp4' }
);
const logEvent = (eventName: string) => {
setEvents(prev => [...prev, `${eventName} at ${new Date().toLocaleTimeString()}`]);
};
useEvent(player, 'onLoadStart', () => logEvent('Load Start'));
useEvent(player, 'onLoad', () => logEvent('Load'));
useEvent(player, 'onBuffer', (buffering) => logEvent(`Buffer: ${buffering}`));
useEvent(player, 'onEnd', () => logEvent('End'));
useEvent(player, 'onSeek', (time) => logEvent(`Seek to ${time}s`));
return (
<VideoView
player={player}
style={{ width: '100%', height: 300 }}
/>
);
}
Buffering State
Track buffering state:
import { useVideoPlayer, VideoView, useEvent } from 'react-native-video';
import { ActivityIndicator, View } from 'react-native';
import { useState } from 'react';
function VideoWithBuffering() {
const [isBuffering, setIsBuffering] = useState(false);
const player = useVideoPlayer(
{ uri: 'https://example.com/video.mp4' }
);
useEvent(player, 'onBuffer', (buffering) => {
setIsBuffering(buffering);
});
return (
<View>
<VideoView
player={player}
style={{ width: '100%', height: 300 }}
/>
{isBuffering && (
<View style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
justifyContent: 'center',
alignItems: 'center'
}}>
<ActivityIndicator size="large" color="white" />
</View>
)}
</View>
);
}
Available Events
The following events can be used with useEvent:
onLoad - Video loaded and ready
onLoadStart - Video started loading
onProgress - Playback progress update
onEnd - Video playback ended
onError - An error occurred
onBuffer - Buffering state changed
onStatusChange - Player status changed
onSeek - Seek operation completed
onPlaybackStateChange - Playing/paused state changed
onPlaybackRateChange - Playback rate changed
onVolumeChange - Volume changed
onReadyToDisplay - Video is ready to display
onTimedMetadata - Timed metadata received
onTextTrackDataChanged - Text track data changed
onTrackChange - Selected track changed
onAudioBecomingNoisy - Audio becoming noisy (Android)
onAudioFocusChange - Audio focus changed (Android)
onBandwidthUpdate - Bandwidth update
onControlsVisibleChange - Controls visibility changed
onExternalPlaybackChange - External playback state changed (iOS)
For detailed information about each event and its data, see the Events documentation.
Examples
import { useVideoPlayer, VideoView, useEvent } from 'react-native-video';
import type { onProgressData, VideoPlayerStatus } from 'react-native-video';
import { View, Button, Text } from 'react-native';
import { useState } from 'react';
function CompleteVideoPlayer() {
const [status, setStatus] = useState<VideoPlayerStatus>('idle');
const [progress, setProgress] = useState(0);
const [duration, setDuration] = useState(0);
const player = useVideoPlayer(
{ uri: 'https://example.com/video.mp4' },
(player) => {
player.volume = 0.8;
player.loop = false;
}
);
useEvent(player, 'onStatusChange', setStatus);
useEvent(player, 'onProgress', (data: onProgressData) => {
setProgress(data.currentTime);
});
useEvent(player, 'onLoad', (data) => {
setDuration(data.duration);
});
useEvent(player, 'onEnd', () => {
console.log('Playback ended');
});
return (
<View>
<VideoView
player={player}
style={{ width: '100%', height: 300 }}
resizeMode="contain"
/>
<Text>Status: {status}</Text>
<Text>
{Math.floor(progress)}s / {Math.floor(duration)}s
</Text>
<View style={{ flexDirection: 'row', justifyContent: 'center' }}>
<Button
title={player.isPlaying ? 'Pause' : 'Play'}
onPress={() => player.isPlaying ? player.pause() : player.play()}
/>
<Button
title="Seek -10s"
onPress={() => player.seekBy(-10)}
/>
<Button
title="Seek +10s"
onPress={() => player.seekBy(10)}
/>
</View>
</View>
);
}
See Also