Make Your React Components Pretty šŸ’…

Mark Brouch
Walmart Global Tech Blog
8 min readSep 27, 2016
I took this picture. With my phone. Art.

At Walmart Labs we do a lot of peer code reviews, which is great because I get to see all sorts of clever ways to write React components from a variety of talented engineers. In this post Iā€™ll share five of my favorite patterns and shortcuts.

But firstā€¦

Why Pretty Code Is Better

Thereā€™s more than one way to skin a cat, and more than one way to write a React component.

However, just because you can write a component any way you see fit doesnā€™t mean you should. Code is meant to be read by humans; computers just interpret whatever jumble of characters you throw at them. šŸ¤–

Your developer peers will thank you if you make your components as pretty on the inside as they are on the outside.

Pretty componentsā€¦

  • šŸ’” are easy to understand even without comments
  • šŸš€ can be even more performant than clunky code
  • šŸ› increase the chances of catching bugs before they reach QA
  • šŸ“ are concise and say a lot with a little

ā€œLess is more.ā€

ā€” Mies van der Rohe

1. The Stateless Functional Component (SFC)

My favorite React component optimization, which is often overlooked, is the Stateless Functional Component, or SFC for short. I love SFCs because they greatly reduce the amount of baggage that comes with extending the React Component class and will offer** performance advantages as an added bonus!

Basically, the SFC will make your application fast and look great doing it.

The Batmobile is an example of a Stateless Functional Component.

**Under the hood, SFCs just get wrapped in a simple Component with a sole render function, but this pattern will soon be able to benefit from additional optimizations:

In the future, weā€™ll also be able to make performance optimizations specific to [SFCs] by avoiding unnecessary checks and memory allocations.

ā€” Ben Alpert, React Blog

A Practical Example

Letā€™s take a look at how an SFC can greatly reduce the amount of code it takes to write the simple Related Search component:

Even as a traditional React.Component extension, it doesnā€™t take much to display a list of related searches:

export default class RelatedSearch extends React.Component {
constructor(props) {
super(props);
this._handleClick = this._handleClick.bind(this);
}
_handleClick(suggestedUrl, event) {
event.preventDefault();
this.props.onClick(suggestedUrl);
}
render() {
return (
<section className="related-search-container">
<h1 className="related-search-title">Related Searches:</h1>
<Layout x-small={2} small={3} medium={4} padded={true}>
{this.props.relatedQueries.map((query, index) =>
<Link
className="related-search-link"
onClick={(event) =>
this._handleClick(query.searchQuery, event)}
key={index}>
{query.searchText}
</Link>
)}
</Layout>
</section>
);
}
}

The SFC alternative, however, offers a 29% lines of code savings!

const _handleClick(suggestedUrl, onClick, event) => {
event.preventDefault();
onClick(suggestedUrl);
};
const RelatedSearch = ({ relatedQueries, onClick }) =>
<section className="related-search-container">
<h1 className="related-search-title">Related Searches:</h1>
<Layout x-small={2} small={3} medium={4} padded={true}>
{relatedQueries.map((query, index) =>
<Link
className="related-search-link"
onClick={(event) =>
_handleClick(query.searchQuery, onClick, event)}
key={index}>
{query.searchText}
</Link>
)}
</Layout>
</section>
export default RelatedSearch;

This amazing reduction in code is accomplished primarily in two ways, stemming from the absence of an ES2015 Class extension:

  • No constructor (5 LOC)
  • Concise render statement using arrow syntax (4 LOC)

Whatā€™s really great about the SFC, however, is the vastly improved readability. First of all, SFCs represent Pure Components in the best way possible by being hyper-focused on returning just the JSX for the component. Removing the constructor, which is no longer needed, and refactoring the _handleClick() function outside of the component also aids in readability as concerns are more clearly separated.

One of my favorite parts of the SFC is how props are clearly defined right up top in the function args list using ES2015 Object Destructuring syntax:

const RelatedSearch = ({ relatedQueries, onClick }) =>

This is both a handy place to see all of the props the component is receiving at a quick glance as well as a way to do away with referencing this.props all over the place, making the code more easily read overall.

When Can SFCs Be Used?

Probably the best part about SFCs is that they can be used just about anywhere a Pure Component can be used. At Walmart Labs, we use Redux to manage the state of our application, which means almost all of our components are candidates for being SFCs.

There are, however, two instances where a stateless component cannot be a SFC:

  • When a component lifecycle method is needed
  • When refs are used

These two instances are fairly uncommon though, and often can be avoided altogether with careful architecture and planning.

2. Conditional Components

JSX does not allow for if statements, so to avoid having to refactor code into submodules just to use conditional logic, try the ternary instead:

render() {
<div class="search-results-container">
{this.props.isGrid
? <SearchResultsGrid />
: <SearchResultsList />}
</div>
}

This expression is awesome at returning one component or another if a condition is met or not met. However, the ternary might not be the best option for cases where a component should either be rendered or not:

render() {
<div class="search-results-list">
{this.props.isSoftSort
? <SoftSortBanner />
: null
}
</div>
}

This works, but itā€™s like telling React to ā€œRender this component, or else!ā€

A more semantic and concise approach is by using the logical AND double ampersand to return the conditional component or false:

render() {
<div class="search-results-list">
{!!this.props.isSoftSort && <SoftSortBanner />}
</div>
}

This is, of course up to personal preference and some people prefer the ternary approach for any conditional component.

Edit ā€” In a previous version of this post I left out the boolean cast !! from the left side operand, which is dangerous because some falsey values like zero may be unintentionally rendered by React. Always cast your left side operand when using &&. Thanks to Reddit users miketa1957, HumansAreDumb, and alexbarrett for pointing this out.

3. Arrow Syntax in React and Redux

ES2015 is full of nifty syntax shortcuts, my favorite of which is the arrow notation. These are especially great when writing components, but I often see them used short of their full potential:

const SoftSort = ({ hardSortUrl, sortByName, onClick }) => {
return (
<div className="SearchInfoMessage">
Showing results sorted by both Relevance and {sortByName}.
<Link
href={`?${hardSortUrl}`}
onClick={(ev) => onClick(ev, hardSortUrl)}>
Sort results by {sortByName} only
</Link>
</div>
);
};

All this function does is return JSX, so we can be even more concise:

const SoftSort = ({ hardSortUrl, sortByName, onClick }) =>
<div className="SearchInfoMessage">
Showing results sorted by both Relevance and {sortByName}.
<Link
href={`?${hardSortUrl}`}
onClick={(ev) => onClick(ev, hardSortUrl)}>
Sort results by {sortByName} only
</Link>
</div>

Thatā€™s a 25% reduction in lines of code ā€” now thatā€™s turning it up to 11!

Use Arrow functions the way they were meant to be!

Another place I often see Arrow functions not living up to their full potential is in Redux mapStateToProps functions:

const mapStateToProps = ({isLoading}) => {
return ({
loading: isLoading,
});
};

Careful here though, when returning an Object, youā€™ll have to wrap it in parentheses:

const mapStateToProps = ({isLoading}) => ({
loading: isLoading
});

Edit ā€” Thanks Victor Storozhenko for pointing out the Object Destructuring improvement in this example.

The point of optimizing Arrow functions is to improve readability by focusing on just the important parts of the function and removing the background noise of unnecessary return statements and brackets.

4. Say What You Mean With Object Destructuring and Spread Attributes

Large components often suffer from this.props syndrome. That is to say, you see the phrase this.props all over the place, which unfortunately detracts from readability by acting as a source of extra noise. Fortunately, with ES2015 Object Destructuring we have a way to concisely write our props in our JSX. Take this example of a Product Price component which has a lot of props to render:

render() {
return (
<ProductPrice
hidePriceFulfillmentDisplay=
{this.props.hidePriceFulfillmentDisplay}
primaryOffer={this.props.primaryOffer}
productType={this.props.productType}
productPageUrl={this.props.productPageUrl}
inventory={this.props.inventory}
submapType={this.props.submapType}
ppu={this.props.ppu}
isLoggedIn={this.props.isLoggedIn}
gridView={this.props.isGridView}
/>
);
}

Wow, thatā€™s a lot of this.props! Hereā€™s a way to cut down on this.props noise:

render() {
const {
hidePriceFulfillmentDisplay,
primaryOffer,
productType,
productPageUrl,
inventory,
submapType,
ppu,
isLoggedIn,
gridView
} = this.props;
return (
<ProductPrice
hidePriceFulfillmentDisplay={hidePriceFulfillmentDisplay}
primaryOffer={primaryOffer}
productType={productType}
productPageUrl={productPageUrl}
inventory={inventory}
submapType={submapType}
ppu={ppu}
isLoggedIn={isLoggedIn}
gridView={isGridView}
/>
);
}

This adds a few lines of code, but it also makes our code much easier to read and clearly points out which props we are using in the component. This makes sense to do in a large component where the same props might be used multiple times and in several subcomponents, but in this simple example we can use Spread Attributes for a super shortcut:

render() {
const props = this.props;
return <ProductPrice {...props} />
}

Stateless Functional Components (as mentioned earlier) make great use of Object Destructuring, since they receive props as an arg:

const ProductPrice = ({
hidePriceFulfillmentDisplay,
primaryOffer,
productType,
productPageUrl,
inventory,
submapType,
ppu,
isLoggedIn,
gridView
}) =>
<ProductPrice
hidePriceFulfillmentDisplay={hidePriceFulfillmentDisplay}
primaryOffer={primaryOffer}
productType={productType}
productPageUrl={productPageUrl}
inventory={inventory}
submapType={submapType}
ppu={ppu}
isLoggedIn={isLoggedIn}
gridView={isGridView}
/>

5. Method Definition Shorthand

This trick might not be incredibly useful, but it sure is pretty. šŸ’…

Whenever you are writing methods in an object, you can use the ES2015 Method Definition Shorthand instead of the boring old ES5 way of doing things. This is especially handy in defaultProps declarations:

Link.defaultProps = {
onClick(event) {
event.preventDefault();
Logger.log(event);
}
};

Plus, if you just want to set a default no-op method, itā€™s super easy:

ProductRating.defaultProps = {
onStarsClick() {}
};

In Conclusion

I hope these tricks Iā€™ve shared help make your React application a more beautiful place and that you will actively think about how you can make your code prettier. Remember, beautiful code does a lot without saying much.

ā€œSpeak softly and carry a big stick.ā€

ā€” Theodore Roosevelt

--

--