LoginSignup
20
9

More than 3 years have passed since last update.

[React] 年末だしwindow.matchMedia()で爆速レスポンシブ対応していこうな

Last updated at Posted at 2019-12-02

はじめに

この記事は [React] 年末だしstyled-componentsで爆速レスポンシブ対応していこうな の続きです。

前回は 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.spMediaQueryList になっており、

media.sp.addListener((e) => { ... })

することでメディアクエリの変更を動的に検知することもできるみたいです。

react-media-hook

lessmess-dev/react-media-hook が近い思想で存在してます。これをつかっても良いですし、どちらにせよwrapしたくなるので、上記のように自分で書いてもいいと思います。

以上です! ありがとうございました!

20
9
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
9