React: Taking your reusability Super Saiyan

I’ve been using React professionally almost everyday for over a year now and I thought it was about time I shared my top tips for creating React components with reusability in mind.

At 7Geese we group all our components in one of two ways. There are groups feature specific/unique of components that are used once for specific situations. The second group is an ever growing library of standard components. In tandem with the design team we are essentially creating a 7Geese style “Bootstrap” of our standard objects/components to ensure consistency throughout the app. The main barrier to this is custom behaviour and those extra small details that can easily break your attempts at creating nice, clean standard components.


#1 Be careful with your CSS properties

My first tip actually has no direct relationship with React at all, but you will quickly see how this straightforward concept blew my mind when I first realised it. Sometimes the seemingly obvious hides right under your nose.

A common component might look like this

class ButtonGroup extends React.Component {
render() {
return (
<div>
<AddButton/>
<DeleteButton/>
<EditButton/>
</div>
);
};
}

Note the outermost div, which I call the “component wrapper”. When building this ButtonGroup you can imagine floating it in the top right corner of a page or perhaps displayed inline? A straightforward solution is to add CSS classes to the component wrapper. STOP! Why might this be a bad thing? Why might this be a good thing?

No floats, no position: absolute/relative, no margins.

What i’m trying to say here isn’t never apply a CSS class to your component wrapper. But you should ban certain types of CSS properties. No floats, no position: absolute/relative, no margins. Why? Anything that would interact with a parent div/component breaks reusability.

If the component always has a float: right applied, it forces the behaviour on any parent that calls this component. Instead, in the parent wrap the component in a div which has the style applied.

class ParentComponent extends React.Component {
render() {
return (
<div>
<div className="pull-right">
<ButtonGroup />
</div>
</div>
);
}
}

#2 Make use of children and PropTypes.node

Let’s say I’m creating a reusable confirmation dialog. It consists of a title, some content the makes up the body and a ButtonGroup containing a confirm and cancel button. passing callbacks to handle the confirm/cancel behaviours is pretty straightforward. The complicated part is how do I create a modal body that takes any kind of content including other components?

One approach I have seen is creating your body as a html string and using _dangerouslySetInnerHtml. The problem with this approach is it starts getting nasty if the body wants to be interactive i.e. a button which performs some action. This handy little tip should solve all your woes.

Create your component as follows

class ConfirmDialog extends React.Component {
static propTypes = {
title: React.PropTypes.string.isRequired,
children: React.PropTypes.node.isRequired,
handleConfirm: React.PropTypes.func.isRequired
}
render() {
return (
<div>
<ModalHeader title={this.props.title}/>
<div className="modal-body">
{this.props.children}
</div>
<ModalFooter onConfirm={this.props.handleConfirm} />
</div>
);
};
}

And then when you call it from another component

...
return (
<div>
<ConfirmDialog title="title" handleConfirm={this.handleConfirm}>
<div> // Put whatever you want in here including other components even with callback
<h1>I can put anything in here</h1>
<input onChange={this.handleInputChange} type="text">
<ButtonGroup editCallback={this.editCallback} ... />
</div>
</ConfirmDialog>
</div>
);
...

Now you can have a dynamic modal body. You can tailor the body for any situation!!

I hope you found these tips helpful. What are some of your top tips? Why not share them with me?