この記事では、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 useMediaQuery
useMediaQuery
は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 minmaxDecision
minmaxDecision
関数は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
を使って、コンポーネントのレンダリングをデバイスや画面幅に応じて最適化することができます。これにより、レスポンシブデザインの実現が容易になります。
ぜひ、このカスタムフックをプロジェクトで活用して、レスポンシブなウェブアプリケーションを作成してください。