Search code examples
reactjsresponsivereact-responsive-carousel

React responsive carousel video transition problem


This is my carousel code

import React, { useRef, useState } from "react";
import { Link } from "react-router-dom";
import { Carousel } from "react-responsive-carousel";
import "react-responsive-carousel/lib/styles/carousel.min.css";
import { FaArrowRightLong } from "react-icons/fa6";
import twitterLogo from "../../../../../public/images/carousel/twitter.png";
import discordLogo from "../../../../../public/images/carousel/discord.png";
import videoOne from "../../../../../public/videos/carousel/Master_Desktop_V002_A.mp4";
import videoTwo from "../../../../../public/videos/carousel/Master_Desktop_V002_B.mp4";
import videoThree from "../../../../../public/videos/carousel/Master_Desktop_V002_C.mp4";
import videOneMobile from "../../../../../public/videos/carousel/Master_Mobile_V002_A.mp4";
import videTwoMobile from "../../../../../public/videos/carousel/Master_Mobile_V002_B.mp4";
import videThreeMobile from "../../../../../public/videos/carousel/Master_Mobile_V002_C.mp4";
import "./Carousel.css";

const items = [
  {
    key: 1,
    video: videoOne,
    videoMobile: videOneMobile,
    h1: (
      <span>
        <span style={{ color: "#D6FA02" }}>think it.</span>
        <br />
        build it.
        <br />
        own it.
      </span>
    ),
    text: (
      <span>
        GET CREATIVE WITH THE ONLY ALL
        <br />
        IN ONE NFT MAKER YOU WILL EVER
        <br />
        NEED.
      </span>
    ),
    buttonLabel: "START BUILDING",
  },
  {
    key: 2,
    video: videoTwo,
    videoMobile: videTwoMobile,
    h1: (
      <span>
        think it.
        <br />
        <span style={{ color: "#D6FA02" }}>build it.</span>
        <br />
        own it.
      </span>
    ),
    text: (
      <span>
        GET CREATIVE WITH THE ONLY ALL
        <br />
        IN ONE NFT MAKER YOU WILL EVER
        <br />
        NEED.
      </span>
    ),
    buttonLabel: "START BUILDING",
  },
  {
    key: 3,
    video: videoThree,
    videoMobile: videThreeMobile,
    h1: (
      <span>
        think it.
        <br />
        build it.
        <br />
        <span style={{ color: "#D6FA02" }}>own it.</span>
      </span>
    ),
    text: (
      <span>
        GET CREATIVE WITH THE ONLY ALL
        <br />
        IN ONE NFT MAKER YOU WILL EVER
        <br />
        NEED.
      </span>
    ),
    buttonLabel: "START BUILDING",
  },
];

function BannerCarousel() {
  const renderCustomIndicator = (clickHandler, isSelected, index) => {
    const indicatorStyles = {
      width: 8,
      height: 8,
      border: "1px solid #d6fa02",
      borderRadius: "50%",
      display: "inline-block",
      margin: "0 4px",
      cursor: "pointer",
      background: isSelected ? "#d6fa02" : "transparent",
    };

    return (
      <li
        style={indicatorStyles}
        onClick={clickHandler}
        key={index}
        role="button"
        tabIndex={0}
      />
    );
  };
  return (
    <Carousel
      showArrows={false}
      showStatus={false}
      showThumbs={false}
      infiniteLoop={true}
      interval={7000}
      autoPlay={true}
      renderIndicator={renderCustomIndicator}
      transitionTime={0}
    >
      {items.map((item) => (
        <div key={item.key}>
          <video
            style={{ width: "100%", height: "100%" }}
            playsInline
            autoPlay
            muted
            loop
            className="desktop__video"
          >
            <source className="h-100" src={item.video} type="video/mp4" />
          </video>
          <video
            style={{ width: "100%", height: "100%" }}
            playsInline
            autoPlay
            muted
            loop
            className="mobile__video"
          >
            <source className="h-100" src={item.videoMobile} type="video/mp4" />
          </video>
          <div className="carousel__overlay">
            <div className="overlay__content">
              <div>
                <h1>{item.h1}</h1>
                <br />
                <p>{item.text}</p>
              </div>
              <br />
              <Link to="/" className="link">
                <button type="button" className="btn__carousel">
                  {item.buttonLabel} <FaArrowRightLong />
                </button>
              </Link>
            </div>
          </div>
          <div className="overlay__logos">
            <Link to="https://twitter.com/" target="_blank">
              <img
                src={twitterLogo}
                alt="twitterLogo"
                style={{ width: "2.68rem", height: "2.68rem" }}
              />
            </Link>
            <Link to="https://discord.com/" target="_blank">
              <img
                src={discordLogo}
                alt="discordLogo"
                style={{ width: "2.68rem", height: "2.68rem" }}
              />
            </Link>
          </div>
        </div>
      ))}
    </Carousel>
  );
}

export default BannerCarousel;

Here I am using 3 different videos for both mobile and desktop. But what I want to do is I want to use one single full length video but still there will be 3 indicators. Those indicators will be disabled but when I click on any indicator like I click on second indicator the video will play from 6 secs, when I click on 3rd indicator the video will play from 13 secs like this. For first indicator video will start from the start. also want to move those text and h1 after specific time and clicking on specific indicators. How can I do that?

I tried using different indicators with 3 different videos but it is not smooth.


Solution

  • I've spun up an example of what I believe you're looking for in this codesandbox: https://codesandbox.io/s/beautiful-dubinsky-7nvwsp?file=/src/Carousel.js

    Key things:

    • autoplay: false on Carousel so it doesn't move to the next slide (other slides besides the first are empty, just so it renders extra buttons for us to override the clicks on)
    • Only put a video in the first slide and put two empty divs after just to render extra buttons. I've used some placeholder mp4 from the internet but you can replace this with whatever video src you need
    • Create and assign a React ref to your video slide so we can access it in the indicator's overridden onClick
    • Use the same technique you've already got in your example, overriding the indicators with renderIndicator but this time use the videoRef.current.currentTime = newTime; snippet to update the time of the current playing video rather than changing slides
    • I've created a little map object to map indicator index to timestamp in the video - you can update or define this whatever way you like