I\'m looking to build a tabs component, where some of the tabs will contain dynamic content. I originally started to follow this tutorial:
Creating a tabs component wit
I had a lot of issues setting this up (Nov 20, 2017) and thought I'd post the final setup here for posterity. I'm using react-router-dom 4.2.2
and material-ui 0.19.4
. Bascially, you want to change the hash (#) when the user clicks tabs, and use the hash to find which tab to display. It works pretty well, but unfortunately it adds a tiny bit of a delay, not sure why and will update if I figure it out.
import React, { Component } from 'react';
import { Tabs, Tab } from 'material-ui/Tabs';
export default class TabsComponent extends Component {
constructor(props) {
super(props);
this.onActive = this.onActive.bind(this);
this.getDefaultActiveTab = this.getDefaultActiveTab.bind(this);
this.tabIndices = {
'#firsttab': 0,
'#secondtab': 1
};
}
onActive(tab) {
const tabName = tab.props.label.toLowerCase();
this.props.history.replace(`#${tabName}`); // https://reacttraining.com/react-router/web/api/history
}
getDefaultActiveTab() {
const hash = this.props.location.hash;
return this.tabIndices[hash];
}
render() {
return (
<Tabs
initialSelectedIndex={this.getDefaultActiveTab()}
>
<Tab
label="FirstTab"
onActive={this.onActive}
>
// ...
</Tab>
<Tab
label="SecondTab"
onActive={this.onActive}
>
// ...
</Tab>
</Tabs>
);
}
}
And... material-ui ^1.0.0-beta.26
import React, { Component } from 'react';
import Tabs, { Tab } from 'material-ui/Tabs';
import Paper from 'material-ui/Paper';
import { withRouter } from 'react-router-dom';
import Resources from '../resources/index.jsx';
import styled from 'styled-components';
const StyledTabs = styled(Tabs) `
margin:5px;
`;
class LinkableTabs extends Component {
constructor(props) {
super(props);
this.getDefaultActiveTab = this.getDefaultActiveTab.bind(this);
this.switchTab = this.switchTab.bind(this);
this.state = {
activeTabIndex: this.getDefaultActiveTab()
}
}
getDefaultActiveTab() {
const hash = this.props.location.hash;
let initTabIndex = 0;
this.props.tabs.forEach((x, i) => {
const label = x.label;
if (`#${label.toLowerCase()}` === hash) initTabIndex = i;
});
return initTabIndex;
}
switchTab(event, activeTabIndex) {
this.setState({ activeTabIndex });
//make shareable - modify URL
const tabName = this.props.tabs[activeTabIndex].label.toLowerCase();
this.props.history.replace(`#${tabName}`);
}
render() {
const { match, location, history, staticContext, ...nonrouterProps } = this.props; //https://github.com/DefinitelyTyped/DefinitelyTyped/issues/13689#issuecomment-296246134
const isScrollable = this.props.tabs.length > 2;
return (
<div>
<Paper>
<StyledTabs
fullWidth
centered
scrollable={isScrollable}
onChange={this.switchTab}
value={this.state.activeTabIndex}
{...nonrouterProps}
>
{
this.props.tabs.map(x => <Tab key={x.label} label={x.label} />)
}
</StyledTabs>
</Paper>
{
this.props.tabs[this.state.activeTabIndex].component
}
</div>
);
}
}
export default withRouter(LinkableTabs);
Yes, this is a perfect job for React Router because it focuses on simplifying the URL redirection process for Single Page Apps.
The use case of tabs for navigation, definitely falls under the scope of React Router. You can use React Router 3 or 4 for this, but the React Router 4 API is on the horizon and the documentation is looking great.
You can find a helpful example on the link above that shows how easy it is to link with tabs. And here is an example that discusses how you can create tabs with custom links.
One of the "gotchas" though that you may want to consider, is that there has been some difficulty restoring the scroll position if you navigate to a different route and then navigate back to the previous route. Here is a thread that discusses this issue further: https://github.com/ReactTraining/react-router/issues/1686.
If restoring scroll position is very important to you, then at this point React Router may not be the best fit for tabs.
Update:
React router v4 has been released, the issue above has been resolved, and now the docs have a guide on how to restore scroll position!