LoginSignup
11
15

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-12-10

できること

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

こんな感じに書くだけで

tab.gif

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

プログラム

公式のReact Tabs component - Material-UIから極力書き換えずにプログラムを作成します。Centered Tab(中央揃え)が気に入ったのでそれにします。
スクリーンショット 2020-12-11 1.42.54.png

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コンポーネントを複数作成するようにします。これで使いまわせるタブが作成できました。使う際はこんな感じ↓

<CenteredTabs labels={['label1', 'label2', 'label3']} />

ただ、これだとまだ各タブのコンテンツが表示できないので、さらに記述していきます。
公式ドキュメントの一番上のSimple Tab(シンプルなタブ)を参考にコンテンツを表示する部分のコードを書きます。各タブのコンテンツのコンポーネントはTabPanelです。

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

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

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

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

tab.gif

11
15
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
11
15