Reputation: 46723
What's the idiomatic React way to write a component that nests specific child components? I know how to write a component that simply wraps props.children
, like this example from React's own docs:
function FancyBorder(props) {
return (
<div className={'FancyBorder FancyBorder-' + props.color}>
{props.children}
</div>
);
}
But what if I wanted to create a pair of components that can be used like this:
<TabSet>
<Tab name="Mammals">
content for <b>warm blooded</b> creatures here
</Tab>
<Tab name="Fish">
content for <b>cold blooded</b> creatures here
</Tab>
</TabSet>
Here's my initial implementation of TabSet
(using reactstrap), simplified to remove styling, selected-tab management, and other stuff not related to this question.
import React, {Fragment, Component} from 'react';
import { TabContent, TabPane, Nav, NavItem, NavLink } from 'reactstrap';
export default class TabSet extends Component {
render(props) {
return (
<Fragment>
<Nav tabs>
{props.children.map((tab,i) =>
<NavItem key={i}>
<NavLink>
{ tab.name }
</NavLink>
</NavItem>
)}
</Nav>
<TabContent>
{props.children.map((tab,i) =>
<TabPane key={i} tabId={i}>
{ tab.children }
</TabPane>
)}
</TabContent>
</Fragment>
);
}
}
Where I'm stuck is how to implement the Tab
component. Logically, it's part of the TabSet
component-- it should never stand alone. And its implementation should be painfully simple because it doesn't actually do anything-- it's just a container for a name
attribute and child elements.
So, here's a few questions:
Tab
component, or is it so simple that I should just export it as part of the implementation of the TabSet
component? If the latter, how?TabSet
, will I need two import
statements, or is there a way I can import both TabSet
and Tab
with one import
, kinda like import React, {Fragment} from 'react'
works ? If the latter, then how would the export statement look in TabSet.js?Apologies for what's probably an obvious question-- I'm a newbie to both React and ES6.
Upvotes: 2
Views: 159
Reputation: 3748
If the component is only used in context of another component it is logical to put them both in same module and many libraries do that. The way to achieve this is use multiple export
statements without default
. You are allowed to use one export default
and as many export
statements as you need. Like this
export default class TabSet
...
export class Tab
and to import
import TabSet, {Tab} from './Tab'
The general syntax being
import defaultExport, { namedExport1, namedExport2 } from "module"
The syntax might seem a bit confusing here is the reference
Upvotes: 1
Reputation: 33179
Where you are using export default class ...
you can actually export your own object here. With that in mind, you are able to something like:
const TabSet = props => (
<Your Tabset markup here>
)
const Tab = props => (
<Your Tab markup here>
)
export {
Tabset,
Tab
}
Doing it like this will allow you to import both components in the one line by doing:
import { Tabset, Tab } from 'wherever'
Now while this is one way to do it, and although you think Tab
is quite simple, I still believe they belong in their own files. So just create the two class files for Tabset
and Tab
, but then make a third file called tabs.js
or something. It should contain the link to both, like:
import Tabset from './tabset'
import Tab from './tab'
export {
Tabset,
Tab
}
This way you have designated files for each component, and you can import them as a single import.
Also for bonus, if you use the PropTypes
ability of react, you can restrict the children of the Tabset
to actually be your Tabs. Here is the overview, but as an example you can do something like:
// untested
static propTypes = {
children: PropTypes.arrayOf(PropTypes.instanceOf(Tab))
}
You will have to import the Tab
component into the set component to do this.
Upvotes: 0