React + Material-UIで簡単なタブ作成


# できること

```react
<CenteredTabs labels={['label1', 'label2', 'label3']}>
    <div>aa</div>
    <div>bb</div>
    <div>cc</div>
</CenteredTabs>
```

こんな感じに書くだけで

![tab.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381461/adcf17a6-89e3-15cc-c136-d2df9b368fe9.gif)

こんな風にタブページを作れるコンポーネントを作成する

# プログラム
公式の[React Tabs component - Material-UI](https://material-ui.com/components/tabs/)から極力書き換えずにプログラムを作成します。Centered Tab(中央揃え)が気に入ったのでそれにします。
![スクリーンショット 2020-12-11 1.42.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381461/42d0a577-7df7-c8ec-1cad-0f7aa1593287.png)


```react
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Paper from '@material-ui/core/Paper';
import Tabs from '@material-ui/core/Tabs';
import Tab from '@material-ui/core/Tab';

const useStyles = makeStyles({
  root: {
    flexGrow: 1,
  },
});

// 引数propsを追加
export default function CenteredTabs(props) {
  const classes = useStyles();
  const [value, setValue] = React.useState(0);

  const handleChange = (event, newValue) => {
    setValue(newValue);
  };

  return (
    <Paper className={classes.root}>
      <Tabs
        value={value}
        onChange={handleChange}
        indicatorColor="primary"
        textColor="primary"
        centered
      >
       {/* 書き換え
        <Tab label="Item One" />
        <Tab label="Item Two" />
        <Tab label="Item Three" />
        */}
      {props.labels.map(label => <Tab label={label}></Tab>)} {/*追加*/}
      </Tabs>
    </Paper>
  );
}

```



propsで配列を受け取ってMaterial-uiのTabコンポーネントを複数作成するようにします。これで使いまわせるタブが作成できました。使う際はこんな感じ↓



```react
<CenteredTabs labels={['label1', 'label2', 'label3']} />
```
ただ、これだとまだ各タブのコンテンツが表示できないので、さらに記述していきます。
公式ドキュメントの一番上のSimple Tab(シンプルなタブ)を参考にコンテンツを表示する部分のコードを書きます。各タブのコンテンツのコンポーネントはTabPanelです。

```react
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Paper from '@material-ui/core/Paper';
import Tabs from '@material-ui/core/Tabs';
import Tab from '@material-ui/core/Tab';
import Box from '@material-ui/core/Box';


const useStyles = makeStyles({
  root: {
    flexGrow: 1,
  },
});

// 追加
const TabPanel = (props) => {
    const { children, value, index, ...other } = props;
  
    return (
      <div
        role="tabpanel"
        hidden={value !== index}
        id={`simple-tabpanel-${index}`}
        aria-labelledby={`simple-tab-${index}`}
        {...other}
      >
        {value === index && (
          <Box p={3}>
            {children}
          </Box>
        )}
      </div>
    );
}


const CenteredTabs = (props) => {
  const classes = useStyles();
  const [value, setValue] = React.useState(0);

  const handleChange = (event, newValue) => {
    setValue(newValue);
  };

  return (
    <div>
        <Paper className={classes.root}>
            <Tabs
                value={value}
                onChange={handleChange}
                indicatorColor="primary"
                textColor="primary"
                centered
            >
                {props.labels.map(label => <Tab label={label}></Tab>)} {/* さっきの */}
            </Tabs>
        </Paper>

        {/* 公式ドキュメントの各タブのコンテンツ
        <TabPanel value={value} index={0}>
            Item One
        </TabPanel>
        <TabPanel value={value} index={1}>
            Item Two
        </TabPanel>
        <TabPanel value={value} index={2}>
            Item Three
        </TabPanel>
        */}
        
        {/* 追加 */}
        {props.children.map((child, index) => 
            <TabPanel value={value} index={index}>{child}</TabPanel>)
        }
    </div>
  );
}

export default CenteredTabs
```

コンポーネント を使う際はこんな感じ↓

```react
<CenteredTabs labels={['label1', 'label2', 'label3']}>
    <div>aa</div>
    <div>bb</div>
    <div>cc</div>
</CenteredTabs>
```

propsで受け取ったchildrenをTabPanelに埋め込むことで、子要素を各タブのコンテンツとして表示させるコンポーネントにすることができました。これで完成です！

![tab.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381461/81f7279d-809c-4950-c516-ec6def8cdd6a.gif)