pure-react-carousel でカルーセルを実装する


こんにちは、 Gaji-Labo フロントエンドエンジニアの石垣です。

今回は React 用カルーセル実装ライブラリである pure-react-carousel でカルーセルを実装する機会があったので、やり方とカスタマイズ方法などをまとめてみたいと思います。

pure-react-carousel とは?

pure-react-carousel は React に最適化されたカルーセル実装ライブラリです。
カルーセルを実装するためのビルトインコンポーネントが用意されており、またデフォルトのCSSスタイルが最低限に抑えられているためスタイルのカスタマイズがしやすいのが特徴的です。

以下のようにビルトインコンポーネントを使って基本的なカルーセルを実装できます。

import React from "react";

import {
  Slider,
  Slide,
  ButtonBack,
  ButtonNext,
  CarouselProvider,
  DotGroup,
} from "pure-react-carousel";

export function SliderExample(): JSX.Element {
  const classes = useStyles();
  return (
    <CarouselProvider // カルーセルを内包するコンポーネント。必須
      naturalSlideWidth={0} // デフォルトのスライドの width 。要素に合わせたい場合 0 にする
      naturalSlideHeight={0} // デフォルトのスライドの height 。要素に合わせたい場合 0 にする
      totalSlides={3} // トータルのスライド数
    >
      <Slider> // スライドを内包するコンポーネント
        <Slide index={0}> // スライドする子要素コンポーネント
          <img src="https://placekitten.com/200/300" alt="first cat image" />
        </Slide>
        <Slide index={1}>
          <img src="https://placekitten.com/300/300" alt="second cat image" />
        </Slide>
        <Slide index={2}>
          <img src="https://placekitten.com/400/300" alt="third cat image" />
        </Slide>
      </Slider>
      <DotGroup /> // スライドを指定番号に切り替えるドットを生成するコンポーネント
      <ButtonBack>Back</ButtonBack> // 前のスライドに遷移するコンポーネント
      <ButtonNext>Next</ButtonNext> // 次のスライドに遷移するコンポーネント
    </CarouselProvider>
  );
}

pure-react-carousel の各コンポーネントで生成される要素はデフォルトではスタイルが最小限しか当たっていないため、カルーセルとして機能させるにはスタイルのカスタマイズが必須です。

以下のようにコンポーネントに className を渡してスタイリング可能です。例では MUI の makeStyles を使ってスタイリングをしています。

const useStyles = makeStyles({
  Slider: {
    overflow: "hidden",
    display: "flex",
    "& ul": {
      listStyle: "none",
      display: "flex",
      margin: 0,
      padding: 0,
    },
  },
});

export function Slider(): JSX.Element {
  const classes = useStyles();
  return (
    <CarouselProvider
      naturalSlideWidth={0}
      naturalSlideHeight={0}
      totalSlides={3}
    >
      <Slider className={classes.Slider}>
        <Slide index={0}>
          <img src="https://placekitten.com/200/300" alt="first cat image" />
        </Slide>
        <Slide index={1}>
          <img src="https://placekitten.com/300/300" alt="second cat image" />
        </Slide>
        <Slide index={2}>
          <img src="https://placekitten.com/400/300" alt="third cat image" />
        </Slide>
      </Slider>
      <DotGroup />
      <ButtonBack>Back</ButtonBack>
      <ButtonNext>Next</ButtonNext>
    </CarouselProvider>
  );
}

これでカルーセルとして動作するようになりました。

1枚目の画像を表示している状態

カスタマイズ

スタイルを変更する

前述の通り各コンポーネントは className を受け取ることが出来るので、好みのCSSフレームワークや className を出力する CSS-in-JS などでスタイリング可能です。

また、Slider コンポーネントで出力される carousel__slider-tray などの class 名が付いた要素には classNameTray props で className を渡せます。

export function SliderExample(): JSX.Element {
  const classes = useStyles();
  return (
    <CarouselProvider
      naturalSlideWidth={0}
      naturalSlideHeight={0}
      totalSlides={3}
    >
      <Slider className={classes.Slider} classNameTray={classes.SliderTray}>
        <Slide index={0}>
          <img src="https://placekitten.com/200/300" alt="first cat image" />
        </Slide>
        <Slide index={1}>
          <img src="https://placekitten.com/200/300" alt="second cat image" />
        </Slide>
        <Slide index={2}>
          <img src="https://placekitten.com/200/300" alt="third cat image" />
        </Slide>
      </Slider>
      <DotGroup />
      <ButtonBack className={classes.ButtonBack}>Back</ButtonBack>
      <ButtonNext className={classes.ButtonNext}>Next</ButtonNext>
    </CarouselProvider>
  );
}

スライド数を表示する

現在のスライド数を表示するコンポーネントはデフォルトでは存在しないので実装する必要があります。

CarouselContext の state から currentSlide を取得し、carouselContext に変更があった際に currentSlide を変更する実装になります。

注意点として、スライド数を表示するコンポーネントは CarouselProvider に内包されている必要があります。

import React, { useContext, useEffect, useState } from "react";

import {
  Slider,
  Slide,
  ButtonBack,
  ButtonNext,
  CarouselProvider,
  DotGroup,
  CarouselContext,
} from "pure-react-carousel";

...

function SlidesCountText({
  totalSlides,
}: {
  totalSlides: number;
}): JSX.Element {
  const carouselContext = useContext(CarouselContext); // CarouselContext を取得
  const [currentSlide, setCurrentSlide] = useState(
    carouselContext.state.currentSlide
  );
  useEffect(() => {
    function onChange() {
      setCurrentSlide(carouselContext.state.currentSlide);
    }
    carouselContext.subscribe(onChange);
    return () => carouselContext.unsubscribe(onChange);
  }, [carouselContext]);
  return (
    <>
      {currentSlide + 1} / {totalSlides}
    </>
  );
}

export function SliderExample(): JSX.Element {
  const classes = useStyles();
  return (
    <CarouselProvider
      naturalSlideWidth={0}
      naturalSlideHeight={0}
      totalSlides={3}
    >
      <SlidesCountText totalSlides={3} />
      ...
    </CarouselProvider>
  );
}

これで現在のスライド数を表示できるようになりました。

2枚目の画像を表示している状態

おわりに

今回は React 用カルーセル実装ライブラリである pure-react-carousel についてご紹介しました。
とてもシンプルなライブラリなので、カルーセルの実装をフレキシブルにカスタマイズする必要がある場合に適していると感じました。
カルーセルを実装する機会があるときの選択肢の一つとしていただければと思います。

Gaji-Laboでは、React経験が豊富なフロントエンドエンジニアを募集しています

弊社ではReactの知見で事業作りに貢献したいフロントエンドエンジニアを募集しています。大きな制作会社や事業会社とはひと味もふた味も違うGaji-Laboを味わいに来ませんか?

もちろん、一緒にお仕事をしてくださるパートナーさんも随時募集中です。まずはお気軽に声をかけてください。お仕事お問い合わせや採用への応募、共に大歓迎です!

求人応募してみる!

タグ


投稿者 Ishigaki Shotaro

未経験から Gaji-Labo に入社。現在は React/TypeScript/Next.js の案件で MUI を使ったコンポーネント組み込みを担当。プロジェクトチームのリードとして共に組み込み作業をしているメンバーの進行管理も行っています。休日はだいたい家で音楽を聴いており、たまにライブに出かけています。