VIVITABLOG

VIVITAで活躍するメンバーの情報発信サイト

デザイナーのための要点解説。Reactで作るシンプルなスライドショーコンポーネント。

f:id:imatomix:20210520172733p:plain

こんにちは、こんなの↑を作ってるデザイナーの@imatomixです。しかし世の中人材難、、、なかなかエンジニアチームが増員してくれないので、今日もコードを書いています。

どうしても採れないなら、中でコードを書ける人を増やすしかないですよね。。。そんなこんなで、今回は内部のメンバーに向けて書いています。それでは、読んでください。「デザイナーのための要点解説。 Reactで作るシンプルなスライドショーコンポーネント。」

スライドショーコンポーネント

今回作ってみたのは、こちら。とてもシンプルなスライドショーケースです。デザイナーであれば自分の作品を見せるときに何かと有用なやつです。1つ持っておくと、webサイトだけでなく展示会なんかでも役に立ちますよ。

コンポーネントの中身と概要

以下がスライドショーコンポーネントの中身です(スタイルは上記codesandboxで見てください)。苦手意識があればあるほど、とても難しそうに見えるかもしれません。ですが、要点さえ抑えればあまり複雑なことはしていないということに気づけます。

// ひとまず細かいことは気にしないでください
import React, { useState, useEffect } from "react";
import { CSSTransition } from "react-transition-group";
import styles from "./Slideshow.module.scss";

// 気にしない気にしない
type Props = {
  sec: number;
  images: string[];
};

// そろそろ始めましょうか
const Showcase: React.FC<Props> = ({ sec = 1000, images = [] }: Props) => {
  // 表示する画像を指定するための変数
  const [count, setCount] = useState(0);

  // 一定時間ごとに表示する画像を切り替える処理
  useEffect(() => {
    const interval = setInterval(() => {
      setCount((count) => {
        return count >= images.length - 1 ? 0 : count + 1;
      });
    }, sec);
    return () => {
      clearInterval(interval);
    };
  }, [images, sec]);

  // 画像表示処理
  const slide = images.map((image, index) => {
    return (
      <CSSTransition
        key={index}
        timeout={sec}
        in={index === count}
        classNames="fade"
        unmountOnExit
      >
        <div style={{ backgroundImage: `url(${image})` }} />
      </CSSTransition>
    );
  });
  return <section className={styles.showcase}>{slide}</section>;
};

export default Showcase;

ここでどんなことをしているのかをものすごくざっくりいうと、

  • 画像を表示する画面があります。
  • 複数の画像の情報(URL)が入った箱(配列)があります。
  • 一定時間ごとに箱の中の1番目の画像、2番目の画像、、、と表示する画像を切り替えていきます。
  • パッパッと切り替わるのは味気ないので、表示はフェードインさせます。

といった流れです。プログラミングを意識しなければ、至ってシンプルな流れです。

要点解説

ここで抑えておく要点は以下の3つです。

  • useState
  • useEffect
  • React Transition Group

1つ1つ見ていきましょう。

useState

Reactの標準機能です。公式ではステートフック(名前がuseから始まるものはフック機能)と言われていますが、それだけだと「なるほど、わからん」となる人も多いでしょう。

簡単に言うと

  • 状態を保持/変更するための機能で、値の変化を画面などに反映してくれるもの

です。身近なエンジニアが「厳密に言うとー」などと語りかけてくるかもしれませんが、今はそんなのは無視しましょう。なるべく簡単に捉えることが大事です。

宣言は以下のように行います。

  const [count, setCount] = useState(0);  // 0はcountの初期値

useState()countsetCountを作成します。 以降、setCountを使用して、countの値を変更します。諸々の都合(今は気にしない)で直接値を入れることはできません。

後述しますが、以下によりcountの値が変化すると表示する画像が切り替ります。

  const slide = images.map((image, index) => {
    return (
      <CSSTransition
        key={index}
        timeout={sec}
        in={index === count}   // 画像の順番と指定したcountの値が同じものを表示する
        classNames="fade"
        unmountOnExit
      >
        <div style={{ backgroundImage: `url(${image})` }} />
      </CSSTransition>
    );

useEffect

Reactの標準機能です。 公式では副作用フックと言われていますが、それだけだと「なるほど、わからん」となる人も多いでしょう。

簡単に言うと、

  • 指定した値に変化があったときにだけ、登録した処理(副作用)を実行してくれる機能

です。身近なエンジニアが、以下略。

このように記述します。

  useEffect(() => {
    // ↓値に変化があったときに実行される処理
    const interval = setInterval(() => {
      setCount((count) => {
        return count >= images.length - 1 ? 0 : count + 1;
      });
    }, sec);
    // ↓上記の処理が再度実行される前に、実行される処理
    return () => {
      clearInterval(interval);
    };
  }, [images, sec]); // ここで登録された値の変更時に上記処理が実行される

setIntervalというJavascriptの機能を使って、一定時間毎にsetCountcountの値を以下の条件で変化させています。

  • 一定時間が立つと
    • count の数字が画像の枚数に達していたら、0にする。
    • それ以外のときはcount の数字に1を足す。

この処理を imagesecの値変更時に実行しているのですが、imageとsecは変化しないので、実際には初回に1回のみ実行されます。

React Transition Group

画像をフェードイン表示する処理には、以下のライブラリを使用してみましょう。

reactcommunity.org

必要なタイミングで画像を表示する要素を生成したり、状態に応じてスタイルを切り替えたり、要らなくなれば削除したり、めんどくさい箇所をやってくれます。 このライブラリを使わずに自前でスタイルの適用を操作するだけでも実装可能だとは思いますが、流れ的に外部ライブラリの1つでも使っとこうかなと思ったので、なんとなく使ってみましょう。

ライブラリをインストールしたら、まずはインポートします。

import { CSSTransition } from "react-transition-group";

あとは、このように画像を表示する要素を<CSSTransition></CSSTransition>で囲めばOKです。

      <CSSTransition
        key={index}  // map処理用
        timeout={sec}  // 表示時間
        in={index === count}   // 画像の順番と指定したcountの値が同じものを表示する
        classNames="fade"   // 適用するフェードスタイルの名前
        unmountOnExit   // 表示が終わったら要素自体を削除する
      >
        <div style={{ backgroundImage: `url(${image})` }} /> // 要素の背景に画像を表示
      </CSSTransition>

これをjavascript の map 機能を使って全画像分行ったものをコンポーネントの結果として親コンポーネントに納品します。

結果、画面上ではcountで指定された順番(index)の画像要素が生成され、フェードアニメーションのスタイルがあてられます。不要な画像要素は削除され、上記のようなスライドショーが完成します。

最後に

プログラミングは細かく、正しく説明しようとすればするほど、どうしても長く、難しくなってしまいます。それが苦手意識やなかなか手を出せない要因になっているのではないでしょうか? ですが、今回やったことも、要点としては前述の通り

  • 画像を表示する画面があります。
  • 複数の画像の情報(URL)が入った箱(配列)があります。
  • 一定時間ごとに箱の中の1番目の画像、2番目の画像、、、と表示する画像を切り替えていきます。
  • パッパッと切り替わるのは味気ないので、表示はフェードインさせます。

なだけなのです。その他の書き方など難しく見える部分は、経験による慣れが必要です。実際のところ、頭で理解して書くのではなく、書いて理解するのです。その繰り返しの結果、頭で理解できるようになります。

その点に関しては、お絵かきと同じですね。