Kaleshe Alleyne-Vassel
Kaleshe Alleyne-Vassel

Reputation: 124

How can you update the props of a single element of an array using state?

I'm trying to create a component that allows a video to autoplay on mouseenter and pauses on mouseleave. However, the current code causes all videos to autoplay when you put the mouseover any single one of the videos. How can I only make the video that you're interacting with update its state in a more isolated way?

I can't seem to find a solution using React hooks anywhere, that I can understand and implement into my own code.

export default function VideoGrid(props) {

    const [playing, setPlaying]  = useState(false);

    return (
        <div>
            <div className={styles.VideoGrid}>
                <div className="container">
                    <h2 className={styles.title + " text-lg uppercase title"}>{props.title}</h2>
                    <div className={styles.videos}>
                        {props.videos ? videos.output.map((video, index) => {
                            return (
                                <div className={styles.video} key={index}>
                                    { video.acf.video_url ? (
                                        <ReactPlayer 
                                            controls={false}  
                                            playing={playing}
                                            onMouseEnter={() => setPlaying(true)}
                                            onMouseLeave={() => setPlaying(false)}
                                            height={205}
                                            url={video.acf.video_url + '&showinfo=0&controls=0&autohide=1'} 
                                            width='100%'
                                            config= {{
                                                youtube: {
                                                playerVars: {showinfo: 0, controls: 0}

                                                }
                                            }}
                                         />

                                    ) : (      
                                        <img src={video._embedded ? video._embedded['wp:featuredmedia'][0].media_details.sizes.full.source_url : '/logo.svg'} height={205} />
                                    )}
                                    <p className="mt-2">{video.title.rendered}</p>
                                    {video.acf.description && router.pathname != '/' ? <p className={styles.description + " text-xs"}>{video.acf.description}</p> : ''}
                                </div>
                            )
                        }) : ''}
                    </div>
                </div>
            </div>
        </div>
    )
}

Upvotes: 0

Views: 28

Answers (1)

Filipe
Filipe

Reputation: 592

You can create a separate component and deal with the state individually.

const Video = (props) => {
  const [playing, setPlaying] = useState(false);

  return (
    <div className={styles.video} key={index}>
      {video.acf.video_url ? (
        <ReactPlayer
          controls={false}
          playing={playing}
          onMouseEnter={() => setPlaying(true)}
          onMouseLeave={() => setPlaying(false)}
          height={205}
          url={video.acf.video_url + "&showinfo=0&controls=0&autohide=1"}
          width="100%"
          config={{
            youtube: {
              playerVars: { showinfo: 0, controls: 0 },
            },
          }}
        />
      ) : (
        <img
          src={
            video._embedded
              ? video._embedded["wp:featuredmedia"][0].media_details.sizes.full
                  .source_url
              : "/logo.svg"
          }
          height={205}
        />
      )}
      <p className="mt-2">{video.title.rendered}</p>
      {video.acf.description && router.pathname != "/" ? (
        <p className={styles.description + " text-xs"}>
          {video.acf.description}
        </p>
      ) : (
        ""
      )}
    </div>
  );
};

export default Video;

Then render it in your map. You need to do the proper changes to pass your data into the video component.

export default function VideoGrid(props) {
  return (
    <div>
      <div className={styles.VideoGrid}>
        <div className="container">
          <h2 className={styles.title + " text-lg uppercase title"}>
            {props.title}
          </h2>
          <div className={styles.videos}>
            {props.videos
              ? videos.output.map((video, index) => {
                  return <Video />;
                })
              : ""}
          </div>
        </div>
      </div>
    </div>
  );
}

Upvotes: 1

Related Questions