I built a simplistic tab container in ReactJS using the idea that the container component keeps in its state an integer index denoting the tab pane to display and then renders only the child (from the this.props.children
array) that is found at that index position.
The gist of this approach was:
const TabContainer = React.createClass({
props: {
tabNames: React.PropTypes.arrayOf(React.PropTypes.string).isRequired
},
getInitialState: function() {
return {
activeIndex: 0
};
},
setTab: function(n) {
this.setState({activeIndex: n});
},
render: function render() {
const childToRender = this.props.children[this.state.activeIndex];
return (
<div className='tab-container'>
<Tabs
tabNames= {this.props.tabNames}
active = {this.state.active}
setTab = {this.setTab}
/>
<div className='tab-pane'>
{childToRender}
</div>
</div>
);
}
});
I.e. only the indexed child is selected and rendered (I've omitted for the sake of simplicity the code handling the edge case where this.props.children
is not an Array
).
I found out that this approach was unsatisfactory as when the user selected different tabs, the component corresponding to the pane to render was mounted and unmounted repeatedly and any state that the panes had could not be preserved.
Ultimately, I used an approach in which all children are rendered and all panes, except the selected one, are assigned a class hidden
that is then used to style those panes as: display:none
. When this later solution was used my panes remained mounted even after the user clicked through the various tabs and any state they had wasn't lost as the user cycled through the tabs.
My questions are:
- was the initial approach (where only a specific child is rendered) an anti-pattern or was there some other mechanism I could have used to preserve the state of the individual panes or prevent them from being unmounted?
- if the initial approach was indeed an anti-pattern how can that anti-pattern be expressed more generally?