1. Pengantar

Pada tutorial sebelumnya saya bahas bagaimana membuat aplikasi Carousel Image Slider menggunakan Vue.js 3 mulai dari nol. Pada tutorial ini saya akan bahas bagaimana membuat aplikasi yang sama dengan menggunakan React.js, React Hooks dan sedikit sentuhan CSS.

2. Membuat project baru React.js

Di tutorial ini saya akan gunakan Vite.js dari pada menggunakan Create React App. Jika kalian belum pernah menggunakan Vite.js sebelumnya, ia adalah semacam build tool yang mendukung Vue 3, React.js, Preact dan Svelte.js.

Selain itu Vite.js jauh lebih ringan dan cepat dalam developmen aplikasi karena tidak menggunakan proses bundling. Sebaliknya ia menggunakan Native ES modul yang sudah disupport oleh browser-browser modern.

Kita buka terminal, kemudian ketikan npm init vite@latest. Pada project name kita isi dengan nama projek yang akan kita buat misalnya react-carousel.

npm init vite@latest
? Project name: › react-carousel

Selanjutnya pada pilihan Select a framework, kita pilih react. Kemudian pada pilihan Select a variant, kita pilih react.

? Select a framework: › - Use arrow-keys. Return to submit.
    vanilla
    vuereact
    preact
    lit
    svelte
    
? Select a variant: › - Use arrow-keys. Return to submit.
❯   react
    react-ts

Jika proses scaffolding projek react berhasil akan tampil seperti berikut. Tinggal kita ikuti instrukti yang ada di bawahnya.

Scaffolding project in /Users/eding/Learn/React/react-carousel...

Done. Now run:

  cd react-carousel
  npm install
  npm run dev

Kita pindah ke projek yang barusan kita buat. Kemudian kita instal paket-paket yang dibutuhkan dengan menggunakan npm install. Setelah instalasi selesai, kita bisa jalankan Local Development Server untuk menjalankan aplikasi React.js kita menggunakan perintah npm run dev.

vite v2.7.6 dev server running at:

  > Local: http://localhost:3000/
  > Network: use `--host` to expose

  ready in 720ms.

Kita bisa akses aplikasi React.js kita dengan alamat http://localhost:3000 di browser. Hasilnya akan tampil seperti gambar berikut.

react-carousel-1.png

3. Project Clean up

Selanjutnya kita buka file App.jsx, kemudian kita ubah isinya seperti kode berikut:

src/App.jsx

function App() {
  return (
    <div className='container'>
      <h1>Hello world</h1>
    </div>
  )
}

export default App

Kita juga bisa hapus file-file yang tidak diperlukan seperti Logo.svg dan App.css. Selanjutnya kita ganti kode css di dalam file index.css seperti berikut.

src/index.css

*,
::after,
::before {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.container {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

Jika kita lihat di browser pesan Hello World akan tampil di tengah-tengah layar.

4. Membuat struktur dasar komponen Carousel

Sekarang mari ganti element h1 di dalam file App.jsx dengan struktur dasar komponen Carousel sebagai berikut:

src/App.jsx

function App() {
	return (
    <div className="container">
      <div className='carousel'>
        <div className="carousel-inner">        
          <div className="carousel-item">
            <img />
          </div>        
        </div>
      </div>
    </div>
  )
}

Selanjutnya kita buat variabel slides berisi 5 link gambar. Di sini saya ambil dari tutorial Vue.js dimana tiap-tiap gambar memiliki lebar 900px dan tinggi 400px.

const slides = [
    "https://picsum.photos/id/1032/900/400",
    "https://picsum.photos/id/1033/900/400",
    "https://picsum.photos/id/1037/900/400",
    "https://picsum.photos/id/1035/900/400",
    "https://picsum.photos/id/1036/900/400",
  ]

Selanjutnya kita lakukan perulangan pada tiap-tiap gambar dengan memanfaatkan fungsi javascript map.

src/App.jsx

function App() {
	const slides = [
		// ...
  ]
  
  return (
    ...
    <div className='carousel'>
      <div className="carousel-inner">
        {slides.map((slide, index) => (
          <div className="carousel-item" key={index}>
            <img src={slide} />
          </div>        
        ))}
      </div>
    </div>
    ...
  )
}

Jika kita ke browser, kita akan lihat gambar-gambar ditampilkan bertumpuk.

5. Membuat komponen Carousel dan CarouselItem

Agar reusable maka kita akan pecah komponen App ke dalam 2 komponen: Carousel dan CarouselItem.

5.1. Komponen Carousel Item

Mari kita buat folder baru di dalam folder src dengan nama carousel. Kemudian kita buat file baru dengan nama CarouselItem.jsx. Kita ke App, kemudian kita pindahkan carousel-item ke dalam CarouselItem.jsx.

Di komponen ini kita membutuhkan slide maka kita akan lewatkan sebagai props.

src/components/carousel/CarouselItem.jsx

export default function CarouselItem({ slide }) {
    return (
      <div className="carousel-item">
        <img src={slide} />
      </div> 
    )
}

5.2. Komponen Carousel

Kembali ke komponen App, kemudian kita cut bagian carousel. Kemudian kita buat file baru di folder carousel dengan nama Carousel.jsx, dan kita paste kode sebelumnya ke dalamnya.

Komponen ine memerlukan slides, sehingga kita perlu definisikan dia sebagai props.

src/components/carousel/Carousel.jsx

export default function Carousel({ slides }) {
    return (
        <div className='carousel'>
            <div className="carousel-inner">
                {slides.map((slide, index) => (
                        
                ))}
            </div>
        </div>
    )
}

Kemudian kita impor komponen CarouselItem sebelumnya, dan kita kembalikan komponen tersebut dalam callback function dari map. Karena komponen tersebut membutuhkan slide, maka kita lewatkan slide dari map ke dalam komponen tersebut melalui atribut slide. Selain itu dalam melakukan looping komponen kita juga perlu tentukan atribut key. Kita isi atribut tersebut dengan index.

src/components/carousel/Carousel.jsx

import CarouselItem from "./CarouselItem"

export default function Carousel({ slides }) {
    return (
        <div className='carousel'>
            <div className="carousel-inner">
                {slides.map((slide, index) => (
                    <CarouselItem slide={slide} key={index} />
                ))}
            </div>
        </div>
    )
}

Terakhir, kita kembali ke komponen App. Di sana kita impor komponen Carousel dan kita panggil komponen tersebut di dalam container. Jangan lupa untuk kita lewatkan slides ke dalam komponen melalui atribut slides.

src/App.jsx

import Carousel from './carousel/Carousel'

function App() {
  const slides = [
  ]
  
  return (
    <div className="container">
      <Carousel slides={slides} />
    </div>
  )
}

export default App

Kembali ke browser, dan kita tidak akan melihat adanya perbedaan di layar. Tetapi pastikan tidak ada error pada console.

7. Membuat style dasar untuk Carousel

Kita ke folder src/componetns/caraousel. Kemudian kita buat file baru dengan nama Carousel.css berisi kode css seperti berikut.

src/components/carousel/Carousel.css

.carousel {
  margin: 0 auto;
  overflow: hidden;
  max-width: 900px;
}

.carousel-inner {
  white-space: nowrap;
}

.carousel-item {
  display: inline-block;
  width: 100%;
}

Kemudian kita ke komponen Carousel dan import file Carousel.css

import "./Carousel.css";

Jika kita ke browser, kita akan lihat hanya akan muncul satu gambar di layar. Tetapi dengan memperkecil zoom layar, kemudian kita lakukan inspeksi pada element, kita akan lihat elemen lain yang tersembunyi.

react-carousel-2.png

8. Memanfaatkan react hook

8.1. Membuat state untuk menampung gambar aktif

Pada komponen Carousel kita lakukan impor useState dan useEffect. Kemudian kita definisikan satu state yang nantinya kita gunakan untuk mencatat index dari slide aktif. Kita beri nilai awal nol (menunjukan gambar pertama dari slides), dan kita beri nama currentSlide. Dengan memanfaatkan useState hook kita juga buat function setCurrentSlide untuk mengganti nilai dari currentSlide.

Untuk menggeser gambar di layar, kita tambahkan inline style pada carousel-inner dengan memanfaatkan CSS transform. Kita gunakan translateX() untuk memberikan efek perpindahan elemen secara horisontal. Nilai negativ yang kita berikan akan membuat efek perpindahan dari kiri ke kanan.

src/components/carousel/Carousel.jsx

import { useState, useEffect } from "react";
// ...

export default function Carousel({ slides }) {
    const [currentSlide, setCurrentSlide] = useState(0)

    return (
        <div className='carousel'>
            <div 
                className="carousel-inner"
                style={{ transform: `translateX(${-currentSlide * 100}%)`}}
            >
                {slides.map((slide, index) => (
                    <CarouselItem slide={slide} key={index} />
                ))}
            </div>
        </div>
    )
}

Jika simpan perubahan, kemudian kita ke browser. Kita tidak akan melihat perubahan apapun. Tetapi jika kita coba ganti nilai awal currentSlide dengan nilai lain, misalnya 2. Kita akan lihat gambar di layar akan berubah.

8.2. Memindahkan gambar secara otomatis

Untuk memindahkan gambar secara otomatis kita akan manfaatkan useEffect dari react hook dan fungsi javascript setInterval.

Untuk sementara kita akan coba tampilkan pesan ke console dengan interval 3000ms (3 detik). Tidak lupa kita kembalikan function dimana didalamnya kita panggil clearInterval.

src/components/carousel/Carousel.jsx

export default function Carousel({ slides }) {
    // ...

    useEffect(() => {
        const slideInterval = setInterval(() => {
            console.log('interval')
        }, 3000)

        return () => clearInterval(slideInterval)
    }, [])

    // ...
}

Dengan demikian interval akan dijalankan pada saat komponen pertama kali dimuat. Dan saat komponen dilepaskan interval akan dihentikan. Jika kita ke browser kita akan lihat pesan 'interval' akan ditampilan setiap 3 detik.

Selanjutnya kita bisa ganti perintah console.log dengan memanggil setCurrentSlide, dimana kita lewatkan arrow function yang akan menentukan nilai currentSlide berikutnya. Kita akan naikan nilai currentSlide dengan satu nilai selama nilai tersebut kurang dari total keseluruhan slide. Jika tidak memenuhi sarat maka kita reset nilai tersebut ke nol.

src/components/carousel/Carousel.jsx

export default function Carousel({ slides }) {
    // ...

    useEffect(() => {
        const slideInterval = setInterval(() => {
            setCurrentSlide(currentSlide => currentSlide < slides.length - 1 ? currentSlide + 1 : 0)
        }, 3000)

        return () => clearInterval(slideInterval)
    }, [])

    // ...
}

Jika kita ke browser, kita akan lihat gambar akan berganti setiap 3 detik. Agar efek perindahan gambar lebih smooth, kita bisa tambahkan efek transition pada carousel-inner di dalam file Carousel.css.

src/components/carousel/Carousel.css

/* ... */
.carousel-inner {
  white-space: nowrap;
  transition: ease 1s;
}

9. Menambahkan Carousel Controls

Setelah kita berhasil menukar gambar secara otomatis, mari kita tambahkan dua buah tombol masing-masing di kiri dan kanan. Kedua tombol tersebut nantinya bisa digunakan untuk memindahkan gambar secara manual ke kiri ataupun kanan.

9.1. Mendefinisikan komponen CarouselControls

Kita buat file baru di folder src/carousel dengan nama CarouselControls.jsx. Di dalamnya kita tambahkan kode berikut.

src/components/carousel/CarouselControls.jsx

export default function CarouselControls() {
    return (
        <div>
            <button className="carousel-control left">Prev</button>
            <button className="carousel-control right">Next</button>
        </div>
    )
}

Selanjutnya kita kembali ke komponen Carousel. Impor komponen CarouselControls dan kita tempatkan setelah carousel-inner.

src/components/carousel/Carousel.jsx

<div className='carousel'>
  <div 
    className="carousel-inner"
    ...
    >
    ...
  </div>
  <CarouselControls />
</div>

Selanjutnya kita tambahkan di Carousel.css kode css berikut.

src/components/carousel/Carousel.css

.carousel-control {
  background-color: rgba(0, 0, 0, 0.5);
  border: none;
  display: inline-block;
  position: absolute;
  height: 50px;
  width: 70px;
  top: calc(50% - 25px);
  color: #f3f3f3;
  cursor: pointer;
}
.left {
  left: 0;
}
.right {
  right: 0;
}

Agar kedua tombol tidak ditempatkan di tepi layar, kita tambahkan position: relative pada carousel.

src/components/carousel/Carousel.css

.carousel {
  /* ... */
  position: relative;
}

9.2. Menambahkan fungsionalitas pada komponen CarouselControls

Kembali ke komponen Carousel, kemudian kita definisikan dua buah function prev dan next berikut.

src/components/carousel/Carousel.jsx

const prev = () => {
  const index = currentSlide > 0 ? currentSlide - 1 : slides.length - 1;
  setCurrentSlide(index);
}

const next = () => {
  const index = currentSlide < slides.length - 1 ? currentSlide + 1 : 0;
  setCurrentSlide(index);
}

// untuk sementara kita komentasi useEffect
/* useEffect() */

Kita lewatkan kedua function di atas ke komponen CarouselControls.

<CarouselControls prev={prev} next={next} />

Kembali ke komponen CarouselControls. Definisikan prev dan next sebagai props. Kemudian kita lewatkan masing-masing dari keduanya untuk penanganan event click.

src/components/carousel/CarouselControls.jsx

export default function CarouselControls({ prev, next }) {
    return (
        <div>
            <button className="carousel-control left" onClick={prev}>Prev</button>
            <button className="carousel-control right" onClick={next}>Next</button>
        </div>
    )
}

Jika kita ke browser dan kita klik tombol Prev/Next gambar akan bergeser ke kiri/kanan.

10. Menghentikan slide interval pada saat hover mouse

Agar slide tidak bergeser saat user mengarahkan pointer mouse pada gambar, ada beberapa hal yang perlu kita lakukan. Pertama, kita impor useRef hook dari react. Kemudian kita panggil useRef dan kita assign ke dalam variabel misalnya dengan nama slideInterval.

Kedua, kita definisikan function dengan nama startSlideTimer. Kita pindahkan pemanggilansetInterval dari useEffect ke dalam function tersebut, dan kita assign ke slideInterval.current. Kembali ke useEffect, dan kita panggil function startSlideTimer().

Ketiga, kita definisikan function lain dengan nama stopSlideTimer. Di dalam function ini kita lakukan pengecekan. Jika slideInterval.current tidak kosong, kita panggil clearInterval dan kita lewatkan slideInterval.current ke dalamnya.

Keempat, kita panggil stopSlideTimer pada definisi function startSlideTimer. Selain itu di dalam useEffect, kita juga panggil stopSlideTimer pada return function.

src/components/carousel/Carousel.jsx

// ...
import { useRef } from "react";

export default function Carousel({ slides }) {
    
    const slideInterval = useRef()

    const startSlideTimer = () => {
      	stopSlideTimer();
        slideInterval.current = setInterval(() => {
            setCurrentSlide(currentSlide => currentSlide < slides.length - 1 ? currentSlide + 1 : 0)
        }, 3000)
    }

    const stopSlideTimer = () => {
      if (slideInterval.current) {
        clearInterval(slideInterval.current)
      }
    }

    useEffect(() => {
        startSlideTimer()

        return () => stopSlideTimer()
    }, [])
  
  	// ...
}

Kelima, kita panggil function startSlideTimer pada masing-masing definisi function prev dan next.

src/components/carousel/Carousel.jsx

const prev = () => {
  startSlideTimer();
  const index = currentSlide > 0 ? currentSlide - 1 : slides.length - 1;
  setCurrentSlide(index);
}

const next = () => {
  startSlideTimer();
  const index = currentSlide < slides.length - 1 ? currentSlide + 1 : 0;
  setCurrentSlide(index);
}

Kembali ke browser, dan pastikan semuanya masih berjalan lancar seperti sebelumnya. Selanjutnya kita ke definisi komponen CarouselItem. Tambahkan sebagai props stopSlide dan startSlide.

Pada carousel-item kita lakukan penanganan event mouse enter dengan memanggil stopSlide. Kita juga lakukan penanganan mouse out dengan memanggil startSlide.

src/components/carousel/CarouselItem.jsx

export default function CarouselItem({ slide, stopSlide, startSlide }) {
  return (
    <div className="carousel-item" onMouseEnter={stopSlide} onMouseOut={startSlide}>
      <img src={slide} />
    </div>
  );
}

Kembali ke definisi komponen Carousel, dan kita lewatkan stopSlideTimer dan startSlideTimer pada pemanggilan komponen CarouselItem.

src/components/carousel/Carousel.jsx

<CarouselItem 
  slide={slide} 
  key={index} 
  stopSlide={stopSlideTimer}
  startSlide={startSlideTimer}
  />

Sekarang jika kita browser, kemudian kita arahkan pointer mouse pada gambar slide, kita akan lihat gambar tidak lagi berganti. Tetapi jika kita arahkan pointer mouse keluar gambar slide, gambar slide akan berganti.

11. Menambahkan Carousel indicators

11.1. Membuat komponen CarouselIndictors

Mari kita ke folder src/components/carousel. Kemudian kita buat file baru dengan nama CarouselIndicators.jsx. Di dalamnya kita tambahkan kode seperti berikut.

src/components/carousel/CarouselIndicators.jsx

export default function CarouselIndicators() {
    return (
        <div className="carousel-indicators">
          <button className="carousel-indicator-item"></button>
          <button className="carousel-indicator-item active"></button>
          <button className="carousel-indicator-item"></button>
        </div>
      );
}

Selanjutnya kita buka file Carousel.css, dan tambahkan kode css berikut.

src/components/carousel/Carousel.css

/* ... */
.carousel-indicators {
  position: absolute;
  transform: translateX(-50%);
  left: 50%;
  bottom: 1.5em;
  z-index: 2;
}
.carousel-indicator-item {
  width: 15px;
  height: 15px;
  border: none;
  background: #fff;
  opacity: 0.5;
  margin: 0.2em;
  border-radius: 50%;
  cursor: pointer;
}
.active {
  opacity: 1;
}

Kembali ke komponen Carousel. Kita muat komponen CarouselIndicators yang barusan kita buat. Dan kita panggil komponen tersebut sebelum CarouselControls.

src/components/carousel/Carousel.jsx

// ...
import CarouselIndicators from "./CarouselIndicators";

export default function Carousel({ slides }) {
    // ...

    return (
        <div className='carousel'>
            <div 
                className="carousel-inner"
            >
                ...
            </div>
            <CarouselIndicators />
            <CarouselControls prev={prev} next={next} />
        </div>
    )
}

Jika kita ke browser, kita akan lihat carousel indicator tampil di bagian tengah bawah. Selain itu carousel indicator yang sedang aktif akan terlihat lebih terang.

react-carousel-3.png

11.2. Membuat carousel indicator dinamis

Sekarang mari kita buat item dari carousel indicator dinamis berdasarkan jumlah gambar slide yang kita berikan. Selain itu kita juga perlu membuat indicator aktif menjadi dinamis.

Kita kembali ke CarouselIndicators, kemudian kita tambahkan sebagai props slides dan currentIndex. Kita lakukan perulangan terhadap slides dengan menggunakan method map, dan kita kembalikan elemen button di dalam setiap iterasi.

Kita perlu menerapkan class active secara dinamis yaitu jika nilai currentIndex sama dengan nilai index.

src/components/carousel/CarouselIndicators.jsx

export default function CarouselIndicators({ slides, currentIndex }) {
    return (
        <div className="carousel-indicators">
          {slides.map((_, index) => (
              <button 
                className={`carousel-indicator-item${currentIndex === index ? ' active' : ''}`}
            ></button>
          ))}
        </div>
      );
}

Kembali ke komponen Carousel. Kemudian kita lewatkan slides dan currentSlide ke dalam komponen CarouselIndicators melalui attribut slides dan currentIndex.

src/components/carousel/Carousel.jsx

<CarouselIndicators slides={slides} currentIndex={currentSlide} />

Jika kita ke browser, kita akan lihat carousel indicator aktif akan berubah secara dinamis sesuai dengan perpindahan gambar slide.

11.3. Menambahkan fungsionalitas komponen

Langkah terakhir yang perlu kita lakukan pada komponen CarouselIndicators adalah dengan membuat setiap item indicator berfungsi.

Masih di komponen Carousel. Kita definisikan function baru dengan nama switchIndex dengan satu argumen index. Di dalam function ini kita panggil starSlideTimer untuk mengontrol slide interval, dan memanggil setCurrentSlide dengan melewatkan index ke dalamnya.

src/components/carousel/Carousel.jsx

const switchIndex = (index) => {
  startSlideTimer()
  setCurrentSlide(index)
}

Selanjutnya kita lewatkan function di atas ke komponen CarouselIndicators melaui atribut switchIndex.

<CarouselIndicators slides={slides} currentIndex={currentSlide} switchIndex={switchIndex} />

Terakhir, kita kembali ke komponen CarouselIndicators. Kita tambahkan switchIndex sebagai props. Pada elemen button kita lakukan penanganan event click dengan memanggil function switchIndex dan melewatkan index ke dalamnya.

src/components/carousel/CarouselIndicators.jsx

export default function CarouselIndicators({ switchIndex }) {
    return (
        <div className="carousel-indicators">
          {slides.map((_, index) => (
              <button 
                ...
                onClick={() => switchIndex(index)}
            ></button>
          ))}
        </div>
      );
}

Jika kita kembali ke browser, kemudian kita coba klik indicator slide. Kita akan lihat gambar slide akan digeser.

12. Mengatur agar komponen Carousel dinamis

Agar komponen Carousel menjadi dinamis, dalam arti user bisa mengatur tingkah laku dari komponen, maka kita tambahkan beberapa props seperti berikut.

src/components/carousel/Carousel.jsx

...
export default function Carousel({ slides, interval = 3000, controls = false, indicators = false, autoPlay = true }) {
    // ...
}

12.1 Pengaturan Slides, interval, controls & indicators

Karena slides sekarang dilewatkan dari komponen induk yang memanggil Carousel, maka kita bisa pindahkan definisi variabel slides tersebut dari dalam komponen Carousel ke komponen App.

Pada definisi function startSlideTimer kita bisa ganti argumen ke dua dari pemanggilan setInterval dengan interval.

Kemudian kita tampilkan komponen CarouselIndicators jika nilai indicators dari props bernilai true. Sama halanya dengan CarouselControls, kita akan menampilkannya jika indicatos bernilai true.

src/components/carousel/Carousel.jsx

export default function Carousel({ slides, interval = 3000, controls = false, indicators = false, autoPlay = true }) {
    // ...

    const startSlideTimer = () => {
        // ...
        slideInterval.current = setInterval(() => {...}, interval)
    }

    // ...

    return (
        <div className='carousel'>
            ...
            {indicators && <CarouselIndicators slides={slides} currentIndex={currentSlide} switchIndex={switchIndex} />}
            {controls && <CarouselControls prev={prev} next={next} />}
        </div>
    )
}

Jika kita ke browser, kita tidak akan lagi melihat tombol Prev dan Next, dan juga slide indikator. Ini terjadi karena dalam props yang kita definisikan kita memberikan nilai bawaan false. Jika anda menginginkan kondisi sebaliknya, anda bisa mengatur nilai bawaan dengan true.

Sekarang untuk mengatur komponen Carousel kita bisa lakukan dengan melewatkan masing-masing atribut seperti berikut ini.

src/App.jsx

import Carousel from './carousel/Carousel'

function App() {
  const slides = [
    "https://picsum.photos/id/1032/1280/400",
    "https://picsum.photos/id/1033/1280/400",
    "https://picsum.photos/id/1037/1280/400",
    "https://picsum.photos/id/1035/1280/400",
    "https://picsum.photos/id/1036/1280/400",
  ]
  
  return (
    <div className="container">
      <Carousel 
        slides={slides} 
        interval={5000} 
        controls={true} 
        indicators={true} />
    </div>
  )
}

export default App

12.2. Pengaturan Auto play

Kita juga bisa menambahkan fitur auto play pada komponen Carousel yang memungkinkan user untuk mengatur apakah gambar slide secara otomatis akan digeser atau tidak.

Yang perlu kita lakukan adalah dengan menambahkan props baru misalnya autoPlay. Kita beri nilai bawaan true agar gambar slide akan ditukar secara otomatis.

Selanjutnya pada definisi function startSlideTimer, kita hanya akan jalankan perintah-perintah yang ada jika autoPlay bernilai true.

Terakhir, pada definisi function stopSlideTimer kita akan jalankan clearInterval jika autoPlay bernilai true.

src/components/carousel/Carousel.jsx

export default function Carousel({ autoPlay = true }) {
    ...


    const startSlideTimer = () => {
        if (autoPlay) {
            stopSlideTimer()
            
            slideInterval.current = setInterval(() => {...}, interval)
        }
    }

    const stopSlideTimer = () => {
        if (autoPlay && slideInterval.current) {
            clearInterval(slideInterval.current)
        }
    }

    ...
}

Dengan demikian, jika kita ingin agar gambar slide tidak ditukar secara otomatis, kita perlu melewatkan atribut autoPlay dengan nilai false.

src/App.jsx

<Carousel slides={slides} autoPlay={false} />

12.3. Pengaturan Lebar Carousel

Hingga saat ini lebar dari slide ditentukan di dalam Carousel.css tepatnya di sini:

src/components/carousel/Carousel.css

.carousel {
  margin: 0 auto;
  overflow: hidden;
  width: 900px; /* <--- */
  position: relative;
}

Jika kita hilangkan definisi with di atas, maka carousel tidak lagi tampil dengan semestinya. Mungkin ada beragam cara yang bisa kita lakukan, tetapi di sini kita akan tambahkan pada definisi komponen Carousel satu props lain yaitu with dengan nilai bawaan 1000.

export default function Carousel({ width=1000 }) {...}

Kemudian pada elemen div dengan class carousel, kita tambahkan inline style seperti berikut.

<div className='carousel' style={{ maxWidth : width }}>

Sekarang jika gambar-gambar yang kita lewatkan pada komponen Carousel memiliki lebar 1200px, agar carousel bisa menampilkan dengan baik, kita perlu tentukan atribut width dengan nilai yang sama.

<Carousel slides={slides} width={1200} />

Jika kita ingin carousel mengikuti lebar layar, kita bisa tentukan width dengan nilai 100%.

<Carousel slides={slides} width="100%" />

13. Penutup & Source code

Demikian untuk pembahasan tentang bagaimana membuat komponen Carousel Image Slider dengan menggunakan React.js dari nol. Semoga bermanfaat :)

Source code lengkap dari tutorial ini bisa anda dapatkan di sini: https://bitbucket.org/edomaru/react-carousel