Skip to main content
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