Search code examples
reactjsreact-player

unmute react-player when fullscreen is toggled from outer component


I have a VideoItem- and a Player-component

In VideoList a button is clicked and is going to fullscreen mode (is working as expected) I will unmute player when fullscreen is clicked.

How can I pass down a "mute" change from VideoList to Player? In my Player I also have a "Unmute" button (which is also working as expected:

This is what I have so far

VideoItem.jsx

import React, { useRef, useState, useEffect } from "react"
import { findDOMNode } from "react-dom"
import screenfull from "screenfull"
import VideoPlayer from "./VideoPlayer"

const VideoList = (videos) => {
  const ref = useRef()

  const toggleFullScreen = () => {
    screenfull.request(findDOMNode(ref.current))
  }

  const unMute = () => {
    console.log("Should pass Mute state to player", muted)
  }
  return (
   <>
     <VideoPlayer
            ref={ref}
            mute={muted}
            videoURL={videoUrl}
     />
     <a
       href="#"
       onClick={e => {
         e.preventDefault()
         unMute()
         toggleFullScreen()
       }}
     >
      Show Fullscreen
     </a>
  )
}

Player.jsx

import React, { forwardRef, useState, useEffect } from "react"
import ReactPlayer from "react-player"
const VideoPlayer = forwardRef((props, ref, mute) => {
  let [muteState, setMuteState] = useState(true)

  return (
    <>
      <i className={`fal fa-volume-${muteState ? "up" : "mute"}`}
         onClick={() => {
           setMuteState(!muteState)
         }}
      />
      <ReactPlayer
          ref={ref}
          muted={muteState}
          loop={true}
          playing={true}
          url={props.videoURL}
        />
    </>
  )
}

Thank you!


Solution

  • When you attempt to set the state from the parent this usually is an indicator that you should move the state up and make the child controlled by the parent:

    const VideoList = (videos) => {
      const player = useRef();
      const [muted, setMuted] = useState(true);
      const [fullscreen, setFullscreen] = useState(false);
    
      const handleToggleMute = () => setMuted(current => !current);
    
      const handleFullscreen = event => {
        event.preventDefault();
        setMuted(false);
        setFullscreen(true);
      };
    
      return (
       <>
         <VideoPlayer
           ref={ref}
           muted={muted}
           fullscreen={fullscreen}
           videoURL={videoUrl}
           onToggleMute={handleToggleMute}
         />
         <a href="#" onClick={handleFullscreen}>Show Fullscreen</a>
      )
    }
    

    Also I would use useEffect together with another state fullscreen to avoid having to forward a ref of the video player.

    const VideoPlayer = ({videoURL, muted, fullscreen, onToggleMute}) => {
      const playerRef = useRef();
    
      useEffect(() => {
          if (fullscreen) {
            const videoElem = playerRef.current.getInternalPlayer();
            screenfull.request(videoElem);
          }
      }, [fullscreen]);
    
      return (
        <>
          <i 
            className={`fal fa-volume-${muted ? "up" : "mute"}`}
            onClick={onToggleMute}
          />
          <ReactPlayer
            ref={playerRef}
            muted={muted}
            loop={true}
            playing={true}
            url={videoURL}
          />
        </>
      )
    }