Элементы интерфейса на React. Выпуск №1. Табы.
В этом уроке мы реализуем простой и гибкий компонент вкладок, позволяющий отобразить абсолютно любой контент внутри.

Добавить наши вкладки в приложение будет очень просто:
<Tabs> <Tab title="Architects 😍"> <p>Британская металкор/маткор группа из Брайтона. Группа известна своим агрессивным и эмоциональным вокалом, переплетающимся с динамичными гитарными партиями.</p> </Tab> <Tab title="Crystal Castles 😜"> <p>Канадская группа, исполняющая экспериментальную электронную музыку.</p> </Tab> <Tab title="Washed out 😢"> <p>Эрнест Грин — американский музыкант и продюсер, более известный под псевдонимом Washed Out.</p> </Tab> </Tabs>
Компонент <Tabs />
Он содержит состояние и знает, какая вкладка отображается в данный момент, обрабатывает изменения для отображения / скрытия других вкладок.
export default class Tabs extends PureComponent {
constructor(props) {
super(props);
this.state = {
// Индекс выбранной вкладки
selectedTabIndex: 0,
};
}
getAdditionalProps = (index, props) => ({
handleClick: this.handleTabClick,
tabIndex: index,
selected: index === this.state.selectedTabIndex,
...props,
});
/**
* Клонируем children(компоненты <Tab />),
* добавляя в каждый нужные нам props:
* - обработчик события клика;
* - индекс вкладки
* - флаг активности.
*/
getChildrenTabsWithProps = () => {
return React.Children.map(this.props.children, (child, index) =>
React.cloneElement(
child,
this.getAdditionalProps(index, child.props)
),
);
};
/**
* Рендерим контент активной вкладки
*/
getActiveTabContent = () => {
const { children } = this.props;
const { selectedTabIndex } = this.state;
const currentChildren = children[selectedTabIndex];
if (currentChildren) {
return currentChildren.props.children;
}
return false;
};
/**
* Переключаем вкладки
*/
handleTabClick = tabIndex => {
this.setState({ selectedTabIndex: tabIndex });
};
render() {
const childrenTabsWithProps = this.getChildrenTabsWithProps();
const tabContent = this.getActiveTabContent();
return (
<div className="Tabs">
<ul className="Tabs__list">{childrenTabsWithProps}</ul>
<div className="Tabs__content">{tabContent}</div>
</div>
);
}
}
Компонент <Tab />
Его цель — просто отобразить вкладку, позволить указать заголовок и вызвать функцию родителя (компонент <Tabs/>) по событию onClick, передав в нее свой индекс.
export default class Tab extends PureComponent {
handleClick = () => {
// Вызываем родительский метод для переключения вкладки
this.props.handleClick(this.props.tabIndex);
};
render() {
return (
<li
className={`Tabs__item ${this.props.selected
? 'Tabs__item--selected'
: ''}`}
onClick={this.handleClick}
>
{this.props.title}
</li>
);
}
}
Вывод
Нам удалось реализовать простой компонент вкладок на React с малым количеством кода, который легко поддерживать и улучшать.
Работу компонентов и весь код вы можете посмотреть в интерактивном демо. Также, в качестве дополнительной практики, можно реализовать возможность указывать активную вкладку по умолчанию.
Все ваши вопросы и замечания вы можете писать на ask@deep.digital.
Полезные ссылки
codesandbox.io - онлайн-редактор для React, Preact, Vue.
StackBlitz - Online VS Code IDE for Angular & React.