LoginSignup
20
17

More than 3 years have passed since last update.

【React】useMediaを使ってレスポンシブ対応

Posted at

概要

use-mediaライブラリを使って、レスポンシブ対応してみます。
各デバイスのサイズに対応するBoolean値(isMobileSite, isTabletSite, isPcSite)を定義してContextを使いアプリケーション全体で共有します。共有されたBoolean値を参照し、各デバイス毎に用意したコンポーネントを出し分けすることでレスポンシブ対応を行います。

環境

  • react v17.0.2
  • use-media v1.4.0
  • typescript v4.1.2

インストール

# npmでのインストール
$ npm install --save use-media
# yarnでのインストール
$ yarn add use-media

実装

MediaQueryProvider

下記役割のコンポーネント、カスタムフックを定義してexportします。

  • デバイスのサイズに対応するBoolean値をContextでアプリケーション全体に共有するためのMediaQueryProvider
  • Providerコンポーネントから共有されたBoolean値を取得するカスタムフックuseMediaQueryContext

各デバイスのブレイクポイントはhttps://hashimotosan.hatenablog.jp/entry/2020/12/06/182327を参考にしました。

Components/Provider/MediaQueryProvider.tsx
import React, { createContext, FC, useContext, useMemo } from 'react';
import useMedia from 'use-media';

type Props = {
  children: React.ReactNode;
};

// アプリケーション全体で共有する値の定義
type Context = {
  // モバイルか?
  isMobileSite: boolean;
  // タブレットか?
  isTabletSite: boolean;
  // PCか?
  isPcSite: boolean;
};

// Contextの生成
// デフォルトはPCとする。
const MediaQueryContext = createContext<Context>({
  isMobileSite: false,
  isTabletSite: false,
  isPcSite: true,
});

// 各デバイスでのサイズを定義
const mediaQueries = {
  mobile: '(max-width: 519px)',
  tablet: '(min-width: 520px) and (max-width: 959px)',
  pc: '(min-width: 960px)',
};

export const MediaQueryProvider: FC<Props> = ({ children }: Props) => {
  const isMobileSite = useMedia(mediaQueries.mobile);
  const isTabletSite = useMedia(mediaQueries.tablet);
  const isPcSite = useMedia(mediaQueries.pc);
  const value = useMemo(() => ({ isMobileSite, isTabletSite, isPcSite }), [
    isMobileSite,
    isTabletSite,
    isPcSite,
  ]);

  return (
    <MediaQueryContext.Provider value={value}>
      {children}
    </MediaQueryContext.Provider>
  );
};

export const useMediaQueryContext = (): Context =>
  useContext(MediaQueryContext);

App

MediaQueryProviderがメインのコンポーネントを囲うようにします

App.tsx
import React from 'react';
import MainComponent from 'components/pages/MainComponent';
import { MediaQueryProvider } from 'components/provider/MediaQueryProvider';

export default function App() {
  return (
    <MediaQueryProvider>
      <MainComponent />
    </MediaQueryProvider>
  );
}

MainComponent

useMediaQueryContextを使用し、全体に共有されたBoolean値を取得し、Trueの場合に対応するコンポーネントを出力するようにします。

components/pages/MainComponent
import React, { FC } from 'react';
import MobileContents from 'components/templates/MobileContents';
import TabletContents from 'components/templates/TabletContents';
import PcContents from 'components/templates/PcContents';
import { useMediaQueryContext } from 'components/provider/MediaQueryProvider';

const MainComponent: FC = () => {
  const { isMobileSite, isTabletSite, isPcSite } = useMediaQueryContext();

  return (
    {isMobileSite && (
      <MobileContents />
    )}
    {isTabletSite && (
      <TabletContents />
    )}
    {isPcSite && (
      <PcContents />
    )}
  );
};

export default MainComponent;

まとめ

今回はReactでレスポンシブ対応を実装するuseMediaを使ってみました。
各デバイスに対応するコンポーネントを作成することで、簡単にレスポンシブ対応が可能になります。

今後も試してみたライブラリなどを共有していきます。

参考サイト

20
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
17