画像が縦長か横長かを判定する React カスタムフックを作る


こんにちは、 Gaji-Labo アシスタントエンジニアの石垣です。

今回は img 要素の幅と高さを取得し、画像が縦長か横長かを判定する React カスタムフックを作ってみたのでご紹介したいと思います。

やりたいこと

例えば縦長か横長かにあわせてスタイルを変えたい場合など、画像が縦長か横長かを判定したいことはままあるかと思います。その際、カスタムフックが用意されていると共通化によるメリットはもちろん、img 要素の処理について考えるコストが削減されるので効率向上に繋がります。

今回はそのようなカスタムフックを useImageOrientation という名前で作ってみます。

useImageOrientation を作る

import { useEffect, useState } from "react";

type Orientation = "landscape" | "portrait" | null;

const createImageElement = (src: string) => {
  return new Promise<HTMLImageElement>((resolve) => {
    const imageElement = new Image();
    imageElement.onload = () => resolve(imageElement);
    imageElement.src = src;
  });
};

export const useImageOrientation = (imageSrc: string): string | null => {
  const [orientation, setOrientation] = useState<Orientation>(null);

  useEffect(() => {
    const handleSetOrientation = async () => {
      const imageElement = await createImageElement(imageSrc);
      setOrientation(
        imageElement.width > imageElement.height ? "landscape" : "portrait"
      );
    };
    handleSetOrientation();
  }, [imageSrc]);

  return orientation;
};

useImageOrientation 自体は画像の src を渡すと画像が縦長か横長かを判定して返すカスタムフックです。縦長の場合は portrait が、横長の場合は landscape が返ってきます。

画像の幅と高さを取得する際に createImageElement という関数を通して取得していますがここが肝です。

このカスタムフックは画像の src を渡す作りになっていますが、画像の幅と高さを取得するだけなら img 要素の onLoad で naturalWidth, naturalHeight を取るやり方でも取得できます。しかしその場合、img 要素は条件分岐等を挟まずに最初からページにレンダリングされている必要があります。動的に画像が渡ってくる際は Promise で img 要素を作成し、その幅と高さを取得するほうがより確実です。

このカスタムフックを使って、例えば画像が縦幅か横幅かに応じてCSSを出し分けることができます。

const orientation = useImageOrientation(src);

return (
  <img
    className={classNames("ExampleImage", {
    "-orientationPortrait": orientation === "portrait",
    "-orientationLandscape": orientation === "landscape",
    })}
    src={src}
    alt={alt}
  />
);

おわりに

今回は img 要素の幅と高さを取得し、画像が縦長か横長かを判定する React カスタムフックについて書きました。

ちょっとしたカスタムフックですが、動的に画像が入ってくる場合は意外とハマりどころが多いのでカスタムフックになっていると効率向上につながりメンテナンスもしやすいかと思います。

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

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

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

求人応募してみる!

投稿者 Ishigaki Shotaro

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