できること
<CenteredTabs labels={['label1', 'label2', 'label3']}>
<div>aa</div>
<div>bb</div>
<div>cc</div>
</CenteredTabs>
こんな感じに書くだけで
こんな風にタブページを作れるコンポーネントを作成する
プログラム
公式のReact Tabs component - Material-UIから極力書き換えずにプログラムを作成します。Centered Tab(中央揃え)が気に入ったのでそれにします。
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に埋め込むことで、子要素を各タブのコンテンツとして表示させるコンポーネントにすることができました。これで完成です!