この記事では、Reactでメディアクエリを簡単に扱うためのカスタムフック useMediaQuery を作成する方法を紹介します。このカスタムフックを使用することで、コンポーネントのレンダリングをデバイスや画面幅に応じて最適化できます。
1. プロジェクトの構成
まず、プロジェクトの構成を確認しましょう。以下のファイルが必要です。
useMediaQuery.ts: カスタムフックuseMediaQueryが定義されています。minmaxDecision.ts:minmaxDecision関数が定義されています。vars.ts: 画面幅の定数Deviceが定義されています。types.ts: 型定義DeviceTypeが定義されています。
2. useMediaQuery の解説
カスタムフック useMediaQuery のコードを見ていきましょう。
const useMediaQuery = (
width: number | keyof DeviceType = Device.tb,
minmax: 'min' | 'max' = 'max'
): boolean => {
const [isMatch, setIsMatch] = useState(() => false)
const breakpoint =
typeof width === 'string' ? minmaxDecision(width, minmax) : width
useEffect(() => {
const isMatches = () =>
window.matchMedia(`(${minmax}-width: ${breakpoint}px)`).matches
const resetIsMatch = () => {
const nowIsMatch = isMatches()
setIsMatch(() => nowIsMatch)
}
resetIsMatch()
window.addEventListener('resize', resetIsMatch)
return () => {
window.removeEventListener('resize', resetIsMatch)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
return isMatch
}
export default useMediaQueryuseMediaQuery は2つの引数を受け取ります。
width: 画面幅の閾値(デフォルトはDevice.tb)minmax: メディアクエリのタイプ('min' または 'max'。デフォルトは 'max')
useState を使って、 isMatch というステートを定義します。これは、メディアクエリがマッチしているかどうかを表す真偽値です。breakpoint は、メディアクエリの閾値を計算します。width が文字列の場合、minmaxDecision 関数を使って計算されます。useEffect を使って、resize イベントリスナーを設定します。このリスナーは、ウィンドウサイズが変更されたときに resetIsMatch 関数を呼び出し、isMatch の値を更新します。
3. minmaxDecision の解説
minmaxDecision 関数のコードを見ていきましょう。
const minmaxDecision = (
width: number | keyof DeviceType,
minmax: 'min' | 'max'
): number => {
let _width: number = typeof width === 'number' ? width : Device[width]
_width = minmax === 'max' ? _width - 1 : _width
return _width
}
export default minmaxDecisionminmaxDecision 関数は2つの引数を受け取ります。
width: 画面幅の閾値またはデバイスタイプのキーminmax: メディアクエリのタイプ('min' または 'max')
この関数は、width が数値の場合、そのままの値を使い、文字列の場合は Device オブジェクトから対応する数値を取得します。そして、minmax が 'max' の場合は、閾値から1を引いた値を返します。これにより、max-width クエリでは、閾値の1ピクセル手前までを対象とすることができます。
4. Device の解説
Device オブジェクトは、画面幅の定数を定義しています。以下のように定義されています。
export const Device: DeviceType = {
pc: 1920,
ct: 1136,
tb: 768,
sp: 428
}これらの定数は、useMediaQuery や minmaxDecision 関数で使用されます。プロジェクトでサポートするデバイスや画面サイズに応じて、適切な値を定義してください。
5. 使用方法
useMediaQuery を使って、コンポーネント内でメディアクエリを扱う方法を紹介します。
// 画面幅
export type DeviceType = {
pc: 1920
ct: 1136 // Contents
tb: 768 //IPad Mini
sp: 428 //iPhone14ProMax
}
import React from 'react'
import useMediaQuery from '@/hooks/useMediaQuery'
import { Device } from '@/styles/vars'
const MyComponent = () => {
const isMobile = useMediaQuery(Device.sp, 'max')
return (
<div>
{isMobile ? (
<p>モバイル画面です</p>
) : (
<p>モバイル画面以外です</p>
)}
</div>
)
}
export default MyComponent上記のコードでは、useMediaQuery を使って、画面幅が Device.sp よりも小さいかどうかを判定しています。isMobile の値に応じて、異なる内容を表示しています。
このように、useMediaQuery カスタムフックを使うことで、コンポーネント内で簡単にメディアクエリを扱うことができます。これにより、レスポンシブデザインを実現しやすくなります。
まとめ
この記事では、Reactでメディアクエリを簡単に扱うためのカスタムフック useMediaQuery の作成方法を紹介しました。また、minmaxDecision 関数や Device オブジェクトの定義方法についても説明しました。useMediaQuery を使って、コンポーネントのレンダリングをデバイスや画面幅に応じて最適化することができます。これにより、レスポンシブデザインの実現が容易になります。
ぜひ、このカスタムフックをプロジェクトで活用して、レスポンシブなウェブアプリケーションを作成してください。