80 lines
2.3 KiB
Markdown
80 lines
2.3 KiB
Markdown
---
|
|
title: Tabs
|
|
tags: visual,state,children,intermediate
|
|
---
|
|
|
|
Renders a tabbed menu and view component.
|
|
|
|
- Define a `TabItem` component, pass it to the `Tab` and remove unnecessary nodes expect for `TabItem` by identifying the function's name in `props.children`.
|
|
- Use the `React.useState()` hook to initialize the value of the `bindIndex` state variable to `props.defaultIndex`.
|
|
- Use `Array.prototype.map` on the collected nodes to render the `tab-menu` and `tab-view`.
|
|
- Define `changeTab`, which will be executed when clicking a `<button>` from the `tab-menu`.
|
|
- `changeTab` executes the passed callback, `onTabClick` and updates `bindIndex`, which in turn causes a re-render, evaluating the `style` and `className` of the `tab-view` items and `tab-menu` buttons according to their `index`.
|
|
|
|
```css
|
|
.tab-menu > button {
|
|
cursor: pointer;
|
|
padding: 8px 16px;
|
|
border: 0;
|
|
border-bottom: 2px solid transparent;
|
|
background: none;
|
|
}
|
|
.tab-menu > button.focus {
|
|
border-bottom: 2px solid #007bef;
|
|
}
|
|
.tab-menu > button:hover {
|
|
border-bottom: 2px solid #007bef;
|
|
}
|
|
```
|
|
|
|
```jsx
|
|
function TabItem(props) {
|
|
return <div {...props} />;
|
|
}
|
|
|
|
function Tabs(props) {
|
|
const [bindIndex, setBindIndex] = React.useState(props.defaultIndex);
|
|
const changeTab = newIndex => {
|
|
if (typeof props.onTabClick === 'function') props.onTabClick(newIndex);
|
|
setBindIndex(newIndex);
|
|
};
|
|
const items = props.children.filter(item => item.type.name === 'TabItem');
|
|
|
|
return (
|
|
<div className="wrapper">
|
|
<div className="tab-menu">
|
|
{items.map(({ props: { index, label } }) => (
|
|
<button onClick={() => changeTab(index)} className={bindIndex === index ? 'focus' : ''}>
|
|
{label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
<div className="tab-view">
|
|
{items.map(({ props }) => (
|
|
<div
|
|
{...props}
|
|
className="tab-view_item"
|
|
key={props.index}
|
|
style={{ display: bindIndex === props.index ? 'block' : 'none' }}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
```jsx
|
|
ReactDOM.render(
|
|
<Tabs defaultIndex="1" onTabClick={console.log}>
|
|
<TabItem label="A" index="1">
|
|
Lorem ipsum
|
|
</TabItem>
|
|
<TabItem label="B" index="2">
|
|
Dolor sit amet
|
|
</TabItem>
|
|
</Tabs>,
|
|
document.getElementById('root')
|
|
);
|
|
```
|