React+Material-UIでスマホのみにタブを表示させる


はじめに

PCとスマホの両方にレスポンシブで対応しないといけないが、スマホのみでタブメニューを表示させたい場合にご参考ください。
React(TypeScript), Material-UIで開発しています。 

やりたいこと

  1. PCではGridを使い縦3列にコンポーネントを配置したい
  2. スマホでは、3つのコンポーネントのどれを表示するか選択できるタブを表示させたい
  3. スマホでは、タブの選択で動的にコンポーネントを1つずつ表示させたい

PCでの表示

スマホでの表示

方針

  1. Material-UIのTabを利用する
  2. State変数を配列で宣言し、スマホとPCで設定する初期値を変える
  3. Tabの選択で、それぞれの数字を配列に入れる
  4. 変数がそれぞれの数字を持っているかいないかで、表示を出し分ける

実装

1.UseStateで宣言

スマホの表示幅を600px未満とし、window.innnerWidthで判定する。Material-UIのGridが600px未満でxsと定義されているため同様にした。PCサイズの場合は、valueTabsに1,2,3の数字を初期値として入れる。スマホサイズの場合は1のみを初期値として入れる。

index.tsx

const [valueTabs, setValueTabs] = useState(window.innerWidth > 600 ?  [1,2,3] : [1])

const handleChangeTabs = (event: React.ChangeEvent<{}>, newValue: number) => {
    setValueTabs([newValue])
  };

2.タブの作成

スマホのみで表示させるため、<Hidden smUP>とする。変数valueTabsは配列のため、配列の一番最初の値のみをvalueに入れる。

index.tsx
<Hidden smUp>
  <Tabs 
    value={valueTabs[0]} 
    onChange={handleChangeTabs} 
    aria-label="ant example" 
    variant="fullWidth"
  >
   <Tab value={1} label="Tab1"  />
   <Tab value={2} label="Tab2"  />
   <Tab value={3} label="Tab3"  />
 </Tabs>
</Hidden>

3. コンポーネントの表示の出し分け

someメソッドを使い、配列の中の特定の値があるかどうかを判定する。 &&条件を使い、条件がtrueの場合にのみ中身を表示をさせる。Grid itemで、PCの場合は3分割( sm={4} )、スマホの場合は全画面表示( xd={12} )を行う。

index.tsx
  {valueTabs.some((a) => a == 1) &&(
   <Grid item xs={12} sm={4} >
    //ここにコンポーネント1の中身を記述
   </Grid>
  )}

完成

index.tsx

import {Tabs,Tab,Hidden,Grid} from "@material-ui/core"

const [valueTabs, setValueTabs] = useState(window.innerWidth > 600 ?  [1,2,3] : [1])

const handleChangeTabs = (event: React.ChangeEvent<{}>, newValue: number) => {
    setValueTabs([newValue])
  };


return (

<Hidden smUp>
  <Tabs 
    value={valueTabs[0]} 
    onChange={handleChangeTabs} 
    aria-label="ant example" 
    variant="fullWidth"
  >
   <Tab  value={1} label="Tab1"  />
   <Tab value={2} label="Tab2"  />
   <Tab value={3} label="Tab3"  />
 </Tabs>
</Hidden>


<Grid container alignItems="stretch" >
  {valueTabs.some((a) => a == 1) &&(
   <Grid item xs={12} sm={4} >
    //ここにコンポーネント1の中身を記述
   </Grid>
  )}

 {valueTabs.some((a) => a == 2) &&(
  <Grid item xs={12} sm={4} >
   //ここにコンポーネント2の中身を記述
  </Grid>
 )}

 {valueTabs.some((a) => a == 3) &&(
  <Grid item xs={12} sm={4} >
   //ここにコンポーネント3の中身を記述
  </Grid>
 )}
</Grid>

)

タブを表示させ、中身を出し分けること自体はMaterial UIの公式サイトの内容で十分ですが、PCではタブを表示させずスマホでのみ表示させたいという場合にあまり参考になる記事が見つからず時間がかかりました。 変数を配列にし、各コンポーネントに該当する数字があるかないかで判断することで、一定シンプルに書くことができました。

参考

MaterialUI公式サイト