React Framework Usage Guide

ZWPlayer provides a dedicated interface package zwplayer-react for the React framework, supporting React 16.8+, 17.x, 18.x, and 19.x versions.

1. Installation Steps

1.1 Install Package

npm i zwplayer-react --save

1.2 Verify Installation

After successful installation, a zwplayer core library directory will be automatically generated in the project’s public directory. This directory must be built and published along with the project.

1.3 Version Requirements

  • React 16.8+ (Hooks support required)
  • Supports Create React App, Vite, Next.js, and other build tools

2. Component Usage

2.1 Basic Usage Example

import React, { useRef } from 'react';
import { ZwPlayer } from 'zwplayer-react';

function VideoPlayer() {
  const playerRef = useRef(null);

  const movieUrl = 'https://cdn.zwplayer.cn/media/VMAP9lxJvRpgn5sP3lV6rQ9qkzQmh5psggso3185.mp4';

  const handlePlayerReady = () => {
    console.log('Player ready event.');
    const player = playerRef.current;
    // Player methods can be called here
  };

  const handlePlayerMediaEvent = (event) => {
    console.log('media event:', event.type);
  };

  return (
    <div className="player-container">
      <ZwPlayer
        ref={playerRef}
        nodeid="main-player"
        murl={movieUrl}
        onready={handlePlayerReady}
        onmediaevent={handlePlayerMediaEvent}
        autoplay={false}
        snapshotButton={true}
        optionButton={true}
        infoButton={true}
        enableDanmu={true}
        chapterButton={true}
        fluid={true}
        disableMutedConfirm={true}
      />
    </div>
  );
}

export default VideoPlayer;

2.2 Danmaku Function Example

import React, { useRef } from 'react';
import { ZwPlayer } from 'zwplayer-react';

function DanmuPlayer() {
  const playerRef = useRef(null);

  const movieUrl = 'https://cdn.zwplayer.cn/media/VMAP9lxJvRpgn5sP3lV6rQ9qkzQmh5psggso3185.mp4';

  const handlePlayerReady = () => {
    console.log('Player ready event.');
    const player = playerRef.current;

    // Add test danmaku
    setTimeout(() => {
      if (player && player.appendDanmu) {
        player.appendDanmu({
          border: '1px solid #ccc',
          text: 'Welcome to ZWPlayer danmaku demo!',
          color: '#ff6b6b'
        });
      }
    }, 3000);
  };

  const handleSendDanmu = (danmuText) => {
    if (!danmuText) return;

    const player = playerRef.current;
    let danmu;

    try {
      const jtext = JSON.parse(danmuText);
      danmu = {
        border: '1px solid #ccc',
        text: jtext['text']
      };
    } catch (e) {
      danmu = {
        border: '1px solid #ccc',
        text: danmuText
      };
    }

    if (player && player.appendDanmu) {
      player.appendDanmu(danmu);
    }
  };

  return (
    <div>
      <ZwPlayer
        ref={playerRef}
        murl={movieUrl}
        onready={handlePlayerReady}
        autoplay={false}
        sendDanmu={handleSendDanmu}
        enableDanmu={true}
        danmuBarId="danmu-controlbar"
        disableMutedConfirm={true}
        fluid={true}
      />

      <div id="danmu-controlbar" className="danmubar"></div>
    </div>
  );
}

export default DanmuPlayer;

Danmaku control bar styles:

.danmubar {
  height: 50px;
  background-color: #232323;
  padding: 8px;
  box-sizing: border-box;
  display: flex;
}

.danmubar .zwp_danmu-controlbar {
  width: 60%;
}

2.3 Logo Watermark Example

import React, { useRef } from 'react';
import { ZwPlayer } from 'zwplayer-react';

function LogoPlayer() {
  const playerRef = useRef(null);

  const movieUrl = 'https://cdn.zwplayer.cn/media/VMAP9lxJvRpgn5sP3lV6rQ9qkzQmh5psggso3185.mp4';
  const poster = 'https://cdn.zwplayer.cn/media/b44c43c90be3521bc352aad1e80f9cd0_thumb.jpg';

  const logoConfig = {
    icon: 'https://cdn.zwplayer.cn/logo.png',
    dock: 'right',      // Position: left, right
    x: '5%',            // Horizontal offset
    y: '5%',            // Vertical offset
    width: '10%',       // Width
    height: '10%',      // Height
    opacity: 70         // Opacity 0-100
  };

  return (
    <ZwPlayer
      ref={playerRef}
      murl={movieUrl}
      logo={logoConfig}
      poster={poster}
      autoplay={false}
      disableMutedConfirm={true}
      fluid={true}
    />
  );
}

export default LogoPlayer;

2.4 Thumbnail Example

import React, { useRef } from 'react';
import { ZwPlayer } from 'zwplayer-react';

function ThumbnailPlayer() {
  const playerRef = useRef(null);

  const movieUrl = 'https://cdn.zwplayer.cn/media/VMAP9lxJvRpgn5sP3lV6rQ9qkzQmh5psggso3185.mp4';

  const thumbnails = {
    url: 'https://cdn.zwplayer.cn/media/b44c43c90be3521bc352aad1e80f9cd0_thumb.jpg',
    width: 160,
    height: 90,
    row: 9,
    col: 9,
    total: 74
  };

  return (
    <ZwPlayer
      ref={playerRef}
      murl={movieUrl}
      thumbnails={thumbnails}
      fluid={true}
    />
  );
}

export default ThumbnailPlayer;

2.5 Chapter Segmentation Example

import React, { useRef } from 'react';
import { ZwPlayer } from 'zwplayer-react';

function ChapterPlayer() {
  const playerRef = useRef(null);

  const movieUrl = 'https://cdn.zwplayer.cn/media/VMAP9lxJvRpgn5sP3lV6rQ9qkzQmh5psggso3185.mp4';

  const handlePlayerReady = () => {
    const player = playerRef.current;

    const chapters = [
      {
        title: "Chapter 1",
        desc: "Chapter 1 description",
        time: 0,
        duration: 50,
        thumb: null
      },
      {
        title: "Chapter 2",
        desc: "Chapter 2 description",
        time: 50,
        duration: 100,
        style: { background: "blue" },
        image: null
      },
      {
        title: "Chapter 3",
        desc: "Chapter 3 description",
        time: 100,
        duration: 200,
        style: { background: "green" },
        image: null
      }
    ];

    if (player) {
      player.setChapters(chapters);
    }
  };

  return (
    <ZwPlayer
      ref={playerRef}
      murl={movieUrl}
      onready={handlePlayerReady}
      chapterButton={true}
      fluid={true}
    />
  );
}

export default ChapterPlayer;

2.6 Route Switching (with React Router)

zwplayer-react has built-in support for react-router-dom. When react-router-dom is installed, the component automatically monitors route changes and safely cleans up player resources before route transitions, preventing DOM access errors.

import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { ZwPlayer } from 'zwplayer-react';

function VideoPage() {
  const playerRef = useRef(null);

  return (
    <ZwPlayer
      ref={playerRef}
      murl="https://cdn.zwplayer.cn/media/video.mp4"
      fluid={true}
    />
  );
}

// Player is automatically safely destroyed on route change
function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/video" element={<VideoPage />} />
        <Route path="/other" element={<div>Other Page</div>} />
      </Routes>
    </BrowserRouter>
  );
}

Note: react-router-dom is an optional dependency and will not affect normal player usage when not installed.

3. Modified Attributes

The attributes of the ZwPlayer component are largely the same as the properties of the native zwplayer constructor parameter object, but zwplayer-react has adjusted some attributes:

Attribute Name Description Notes
murl Media address parameter (can be string, object, or array type). If this attribute changes during runtime, the component will automatically call the play method to open the new address. By changing the bound state variable, you can dynamically switch playback programs. Behavior changed
nodeid Used for the id of the ZwPlayer component’s top-level parent div. If not provided, the component will automatically generate one. Added
zwplayerlib zwplayer library address. zwplayer-react uses a dynamic loading mechanism at the underlying level, and will not compile the underlying zwplayer library into the project with React’s build command. This allows for direct replacement of the zwplayer library file after the project is compiled and published for seamless upgrades. This parameter can be omitted; if omitted, the path zwplayer/zwplayer.js in the public directory is used. Added
danmuBarId Used to locate the id of the div element for the zwplayer danmaku input control bar. Providing this parameter avoids calling the buildDanmuControlbar function to create a danmaku control bar. The control bar’s class name is zwp_danmu-controlbar. Added
style Inline style object applied to the player container div. Added
videoprop Video element property object, can contain url and videostyle properties. Added
onready Player initialization completed callback function, receives the player instance as parameter. Event property
onmediaevent Media event callback function, receives the event object as parameter. Event property
onneterror Network error callback function. Event property
onnetclose Network close callback function. Event property
onFileSelected File selection callback function. Event property
onFileLoaded File loaded callback function. Event property
Other Please refer to the parameter description of the zwplayer player constructor.

Common Attributes Description

Display Control Related:

  • autoplay: Whether to autoplay (boolean, default false)
  • fluid: Whether to enable fluid layout (boolean, default false)
  • snapshotButton: Whether to show the snapshot button (boolean)
  • optionButton: Whether to show the option button (boolean)
  • infoButton: Whether to show the info button (boolean)
  • chapterButton: Whether to show the chapter menu button (boolean)
  • enableDanmu: Whether to enable danmaku function (boolean)

Media Related:

  • murl: Media address (string, object, or array)
  • poster: Poster image address (string)
  • thumbnails: Thumbnail configuration (object)

Function Related:

  • sendDanmu: Danmaku send callback function (function)
  • disableMutedConfirm: Whether to disable muted confirmation (boolean)
  • keepAudioWindow: Whether to keep audio window (boolean)
  • localPlayback: Whether to play locally (boolean)
  • recordButton: Whether to show record button (boolean)
  • segmentButton: Whether to show segment button (boolean)

4. Method Calls

The ZwPlayer component exposes player methods through React’s forwardRef + useImperativeHandle pattern. Use useRef to get the component reference and call methods.

4.1 Obtaining Player Instance

import React, { useRef } from 'react';
import { ZwPlayer } from 'zwplayer-react';

function VideoPlayer() {
  const playerRef = useRef(null);

  const handlePlayerReady = () => {
    const player = playerRef.current;
    console.log('Player instance:', player);
  };

  return (
    <ZwPlayer
      ref={playerRef}
      murl="video.mp4"
      onready={handlePlayerReady}
    />
  );
}

4.2 Common Methods

// Play/Pause/Resume/Stop
playerRef.current.play();
playerRef.current.pause();
playerRef.current.resume();
playerRef.current.stop();

// Seek to specified time (seconds)
playerRef.current.seekTime(30);

// Add danmaku
playerRef.current.appendDanmu({
  border: '1px solid #ccc',
  text: 'This is a danmaku message',
  color: '#ff6b6b'
});

// Set chapters
playerRef.current.setChapters([{
  title: "Chapter 1",
  desc: "Chapter 1 description",
  time: 0,
  duration: 50
}]);

// Get current playback time
const currentTime = playerRef.current.getCurrentTime();

// Get total video duration
const duration = playerRef.current.getDuration();

// Volume and mute
playerRef.current.setMute(true);

// Fullscreen
playerRef.current.setullscr(true);

// Subtitles
playerRef.current.addSubtitle('https://example.com/subtitle.vtt', 0, 'English');
playerRef.current.removeSubtitle();

// Danmaku control
playerRef.current.setEnableDanmu(true);

// Danmaku control bar
playerRef.current.buildDanmuControlbar('danmu-bar-id', 'custom-class');

// Notify size change
playerRef.current.notifyResize(800, 450);

// Light control
playerRef.current.lightOff();
playerRef.current.lightOn();

// Get raw player instance (advanced usage)
const rawPlayer = playerRef.current.player;

// Destroy player
playerRef.current.destroy();

5. StrictMode Compatibility

React 18’s StrictMode triggers useEffect twice in development mode, which may cause duplicate player creation. zwplayer-react includes a built-in instance caching mechanism to handle this:

  • Uses window.__zwplayer_instances__ global Map to track player instances
  • Automatically reuses existing instances when duplicate creation is detected
  • Safely cleans up all resources (timers, ResizeObserver, DOM references, etc.) on component unmount

Note: This mechanism does not incur additional overhead in production mode.

6. Example Repositories

7. Notes

7.1 Project Configuration

  1. Directory Structure: Ensure a public directory exists in the project before installation.
  2. Core Library: The public/zwplayer directory must be published along with the project.
  3. Dynamic Loading: zwplayer uses a dynamic loading mechanism that supports seamless upgrades and will not be packaged into the final bundle.
  4. Method Calls: Call player methods via useRef references.

7.2 Best Practices

  1. Use Conditional Rendering to Control Display

    {showPlayer && (
      <ZwPlayer
        ref={playerRef}
        murl={movieUrl}
        fluid={true}
      />
    )}

    Use conditional rendering (&& or ternary operator) instead of CSS hiding to ensure the player is initialized and destroyed correctly.

  2. Wait for Player Ready Before Calling Methods

    const handlePlayerReady = () => {
      const player = playerRef.current;
      // Methods can only be called after player is ready
      player.seekTime(30);
    };
  3. Dynamic Video Switching

    Directly modify the murl state value, and the component will automatically reload:

    const [videoUrl, setVideoUrl] = useState('video1.mp4');
    // Switch video
    setVideoUrl('video2.mp4');
  4. Responsive Layout

    .player-container {
      width: 100%;
      max-width: 1280px;
      margin: 0 auto;
    }
    
    @media (max-width: 768px) {
      .player-container {
        width: 100%;
        height: auto;
        aspect-ratio: 16/9;
      }
    }

7.3 Common Questions

Q: Why is the player not displaying?

A: Check the following points:

  1. Ensure the media URL is accessible.
  2. Check the browser console for error messages.
  3. Confirm the public/zwplayer directory exists and contains required files.
  4. Confirm using {showPlayer && <ZwPlayer ... />} instead of CSS hiding.

Q: How to dynamically switch videos?

A: Directly modify the murl state value:

const [videoUrl, setVideoUrl] = useState('video1.mp4');
setVideoUrl('new-video-url.mp4');

Q: Why are there two players in StrictMode?

A: This is expected behavior in React 18 StrictMode. zwplayer-react has a built-in instance caching mechanism to automatically handle this issue without additional configuration.

Q: How to customize danmaku control bar styles?

A: Control directly through CSS class names:

.danmubar .zwp_danmu-controlbar {
  width: 60%;
  background-color: #232323;
}

Q: How to get the current status of the player?

A: Call the corresponding methods after obtaining the component reference via useRef:

const player = playerRef.current;
const currentTime = player.getCurrentTime();
const duration = player.getDuration();

7.4 Project Structure Recommendations

Create React App Project Structure:

your-react-project/
├── public/
│   └── zwplayer/           # Player core library (auto-generated, must be published)
├── src/
│   ├── components/
│   │   └── VideoPlayer.jsx  # Player wrapper component
│   ├── pages/
│   │   └── VideoPage.jsx    # Page using the player
│   ├── App.jsx
│   └── index.js
├── package.json
└── vite.config.js (or react-scripts)

7.5 Debugging Suggestions

  1. Listen to Player Ready Event

    const handlePlayerReady = () => {
      console.log('Player ready:', playerRef.current);
    };
  2. Listen to All Media Events

    const handlePlayerMediaEvent = (event) => {
      console.log('Media event:', event.type, event);
    };
  3. Use Browser Developer Tools

    • Check network requests to confirm zwplayer.js loads correctly.
    • Check the console for error messages.
    • Use the element inspector to view the DOM structure.

7.6 Performance Optimization

  1. Lazy Loading: For non-above-the-fold players, use conditional rendering for lazy loading.
  2. Destroy Instances: Player instances are automatically cleaned up when components unmount.
  3. Resource Preloading: Consider preloading for key videos.
  4. CDN Acceleration: Deploy the zwplayer core library to a CDN and specify it using the zwplayerlib attribute.

8. Changelog

  • v1.0.5: Support React 19, added route-safe switching
  • v1.0.4: Added thumbnails, chapters, danmaku, and other features
  • v1.0.2: Optimized StrictMode compatibility
  • v1.0.1: Initial version, supports basic playback functions