はじめに
この記事は [[React] 年末だしstyled-componentsで爆速レスポンシブ対応していこうな] (https://qiita.com/nerikosans/items/b2f6934347563d9a2587) の続きです。
前回は styled-components 内でレスポンシブを爆速にする方法を書きましたが、この方法では「端末がモバイルのときだけrender
」といったことはできません。
例えば以下のようにすれば
const SPOnlyBox = styled.div`
background: black;
/* PC */
${media.pc`
display: none;
`}
`;
一応PC上でDOMを見えなくすることはできますが、これだとDOMそのものは残ってしまいますね。
ということで、便利な解決策を考えていきます。
目標
最近のReactはまさに大 hooks 時代です。仮に useMedia
っていうhookがあって、端末がモバイルかPCか、こんなふうに書けたら嬉しいですよね。
const media = useMedia();
const isSP = media.sp;
return (
<div>
{ isSP && <SPOnlyBox /> }
</div>
)
これを目指します!
Solution: window.matchMedia()
つかうもの
世の中には便利なものがあるんですね。ブラウザ標準で、CSS media query形式から、それが現在の環境に合致するかどうか判定してくれる関数があります。
Window.matchMedia() - Web APIs | MDN
この関数を使えば次のようになります。
const isSP = window.matchMedia('screen and (max-width: 767px)').matches;
hook化する
上記の状態で事は済んでいますが、hooksとして共通化しましょう。
export const useMedia = () => {
const queryStrings = {
pc: 'screen and (min-width: 768px)',
sp: 'screen and (max-width: 767px)',
short: 'screen and (max-height: 480px)',
};
return Object.fromEntries(
Object.entries(queryStrings).map(([k, v]: [string, string]) => [
k,
window.matchMedia(v),
])
);
};
できあがり
これで問題ありません。以下のように書けます。
const media = useMedia();
const isSP = media.sp.matches;
実に簡潔で最高ですね。
補足
event listener
このとき media.sp
は MediaQueryList
になっており、
media.sp.addListener((e) => { ... })
することでメディアクエリの変更を動的に検知することもできるみたいです。
react-media-hook
lessmess-dev/react-media-hook が近い思想で存在してます。これをつかっても良いですし、どちらにせよwrapしたくなるので、上記のように自分で書いてもいいと思います。
以上です! ありがとうございました!