0

I have been trying to update my videos so that only one will be playing at a time whenever another video is clicked my state seems to be undefined after clicking the play button and i am not too sure why or if this is the best way to go about what i am trying to achieve can anyone help me out?

This is my main component:

const [allVideos, setAllVideos] = useState(initVideos(data));

 function generateVideo(data, index) {
    return {
      url: data[index].url,
      id: data[index].id,
      playing: false,
    };
  }

  function initVideos(data) {
    const videos = [];

    for (let i = 0; i < data.length; i++) {
      videos.push(generateVideo(data, i));
    }
   
    return videos;
  }
  const videos = allVideos.map((item) => {
    return (
      <>
        <Playlist url={item.url} id={item.id} playing={item.playing} />
        <button onClick={() => playVideo(item.id)}>Play</button>
      </>
    );
  });

  function playVideo(id) {

    setAllVideos((oldVideos) => {
      oldVideos.map((video) => {
        return video.id === id
          ? { ...video, playing: !video.playing }
          : { ...video, playing: false };
      });
    });


  }
  

  return (
    <div className="sidebar-container" style={styles.container}>
      <button className="add-playlist" onClick={(props) => addPlaylist()}>
        Add New Playlist
      </button>
      <p>sidebar for now!</p>
      {videos}
    </div>
  );
}

here is my playlist component which the array is made up of:

 return (
    <div className="playlist-container">
      <Container>
        <ReactPlayer url={props.url} id={props.id} playing={props.playing} />
      </Container>

      <p>This is the playlists name {props.name}</p>
      <p>The playlist is {props.playtime} long</p>
    </div>
  );
}

can anyone suggest how to solve my issue or a better way about making sure only a single video can play at a time?

2 Answers 2

1

The issue was that you were not retuning the map result in your playVideo function. You have to return the map array result as well.

Code:

 function playVideo(id) {
  
    setAllVideos((oldVideos) => {
      return oldVideos.map((video) => {
        return video.id === id
          ? { ...video, playing: !video.playing }
          : { ...video, playing: false };
      });
    });
  }
Sign up to request clarification or add additional context in comments.

5 Comments

that seems to update the object now but the playing property updates but it doesnt play the videos do i need to re render or am i doing that already
when you call setState( update your state) its automatically cause a re render. I think now you to check your library prop which your using to play video to see how you can achieve that behavior
yeah i did playing set as false should pause video and true should play the video weirdly enough the components props are being updated correctly now but playing isn't having any effect @Alpha
I just check your component code <ReactPlayer url={props.url} id={props.id} playing={false} /> shouldn't you bind the playing props as well ? or its a type meaing it should b like this <ReactPlayer url={props.url} id={props.id} playing={props.playing} />
yeah i should of done that i noticed that earlier on but thanks i should update the question
1

The issue is already described but i'd recommend you to simplify your code a bit. And keep an eye on key props, anything that is inside .map should have a unique key at top level fragment. So i replaced your <> with <React.Fragment key={}...

import React, { useMemo, useState } from "react";
import ReactPlayer from "react-player";

const data = [
  { url: "https://www.youtube.com/watch?v=ysz5S6PUM-U", id: "1" },
  { url: "2", id: "2" },
  { url: "3", id: "3" },
  { url: "4", id: "4" },
  { url: "5", id: "5" }
];

export default function App() {
  const allVideos = useMemo(() => data, []);
  const [playingVideoId, setPlayingVideoId] = useState();

  const videos = allVideos.map((item) => {
    return (
      <React.Fragment key={item.id}>
        <Playlist
          url={item.url}
          id={item.id}
          playing={item.id === playingVideoId}
        />
        <button onClick={() => playVideo(item.id)}>Play</button>
      </React.Fragment>
    );
  });

  function playVideo(id) {
    setPlayingVideoId((prev) => (prev === id ? undefined : id));
  }

  function addPlaylist() {}

  return (
    <div className="sidebar-container">
      <button className="add-playlist" onClick={(props) => addPlaylist()}>
        Add New Playlist
      </button>
      <p>sidebar for now!</p>
      {videos}
    </div>
  );
}

const Playlist = (props) => {
  return (
    <div className="playlist-container">
      <div>
        <p>
          {props.url} {props.id}
        </p>
        <ReactPlayer url={props.url} id={props.id} playing={props.playing} />
      </div>

      <p>This is the playlists name {props.name}</p>
      <p>The playlist is {props.playtime} long</p>
    </div>
  );
};

Edit bold-mountain-34lsen

And a little note: You might get some issues with autoplay due to browser's policy. But after you click on play button once visited the page (you can refresh the page or come back later) - autoplay will continue to work normally.

Chrome's autoplay policies are simple: Autoplay with sound is allowed if: The user has interacted with the domain (click, tap, etc.). On desktop, the user's Media Engagement Index threshold has been crossed, meaning the user has previously played video with sound. The user has added the site to their home screen on mobile or installed the PWA on desktop. Top frames can delegate autoplay permission to their iframes to allow autoplay with sound.

Additionally: ReactPlayer repo readme has some notes about autoplay:

As of Chrome 66, videos must be muted in order to play automatically. Some players, like Facebook, cannot be unmuted until the user interacts with the video, so you may want to enable controls to allow users to unmute videos themselves. Please set muted={true}.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.