'React router component not destroying when user leaves the page

I have a video player (jsmpeg player) that opens up a websocket to a server to play live video. The way the video server works is that it counts the number of clients connecting. It starts streaming at clients > 0. This part works. When my video player was in a standalone react-app all by itself it handled everything nicely when I would close the tab/reopen.

I adjusted to using react-router. I want the same sort of logic but instead of opening and closing a tab I'm going to a new react-router page. I have a home page and a player page. When I open the player page it works well, the server realizes a client connects and starts, but when I go back to the home page it "stays alive" and doesn't seem to unmount/end the connection. When I go back to the player page it opens up a second connection, so on and so forth, until I close the tab which terminates all the clients.

How can I close the player when I navigate away from the page? I want navigating off of player.js to function just like closing a tab. The component can re-render/mount when I navigate back to player.

My app.js

import React, { Component } from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';

import Home from './components/Home';
import About from './components/About';
import Contact from './components/Contact';
import Error from './components/Error';
import Navigation from './components/Navigation';
import Player from './components/Player.js';
class App extends Component {
  render() {
    return (
       <BrowserRouter>
        <div>
          <Navigation />
            <Switch>
             <Route path="/" component={Home} exact/>
             <Route path="/player" component={Player}/>
            <Route component={Error}/>
           </Switch>
        </div>
      </BrowserRouter>
    );
  }
}

export default App;

My Player

import React from 'react';
import JsmpegPlayer from './JsmpegPlayer';
import '../App.css';

const videoOptions = {
  poster: ''
};

const videoOverlayOptions = {autoplay: true};

const player = () => {
    return (
      <div>
        <header>
          <JsmpegPlayer
            wrapperClassName="video-wrapper"
            videoUrl="ws://<my ip>:9999"
            options={videoOptions}
            overlayOptions={videoOverlayOptions}
          />
        </header>
      </div>
    );
}

export default player;

The jsmpeg player

import React, {Component} from 'react';
import JSMpeg from '@cycjimmy/jsmpeg-player';

export default class JsmpegPlayer extends Component {
  constructor(props) {
    super(props);

    this.els = {
      videoWrapper: null,
    };
  };

  render() {
    return (
      <div
        className={this.props.wrapperClassName}
        ref={videoWrapper => this.els.videoWrapper = videoWrapper}>
      </div>
    );
  };

  componentDidMount() {
    // Reference documentation, pay attention to the order of parameters.
    // https://github.com/cycjimmy/jsmpeg-player#usage
    console.log('I was triggered during componentDidMount')
    new JSMpeg.VideoElement(
      this.els.videoWrapper,
      this.props.videoUrl,
      this.props.options,
      this.props.overlayOptions
    );
  };
};


Solution 1:[1]

You need to destroy your JSMpeg instance when the component un-mounts. Save the instance when it is created like so this.videoPlayer = new JSMpeg.VideoElement(...) and then in the componentWillUnmount call this.videoPlayer.destroy()

You will need to do this for most third party libraries because the instance will continue to live in memory and that can build up over time causing memory leaks

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Andrew Axton