Skip to main content

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

player
VideoPlayer
required
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
callback
function
required
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

() => void

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

Build docs developers (and LLMs) love