Wednesday, January 28, 2015

An opinionated guide to React.js best practices and conventions

I’ve been using React.js for a little while now, both in my 9 to 5 job and for my own projects, and during that time I have started evolving my own set of React.js best practices.


The following guidelines mostly focus on component structure and JSX. However, they are not hard and fast rules, but more of an opinionated set of guidelines I choose to adhere to that make my code more readable, more robust and easily maintainable.


Note: This article does not provide explanations of the React paradigms or idioms mentioned here or used in the examples, that is best left to the excellent documentation provided by the React team.


Component organisation


As with any code, it’s important to have consistency. This of course also applies when structuring your React components. I use the following pattern:




React.createClass({

propTypes: {},
mixins : [],

getInitialState: function() {},
getDefaultProps: function() {},

componentWillMount : function() {},
componentWillReceiveProps: function() {},
componentWillUnmount : function() {},

_parseData : function() {},
_onSelect : function() {},

render : function() {}

})


I like to declare propTypes at the top of my component as they are a useful guide to a components expected usage (see section below for more on this), followed by the mixins because it is handy to initially know exactly what external behaviours the component is using/dependent on.


I choose to split the life-cycle methods into those that occur before an instance of the component is created (e.g. getInitialState, getDefaultProps) and those which occur during the mounting/updating/mounted cycle (e.g. componentWillMount, shouldComponentUpdate). Furthermore, I find that declaring the lifecycle methods in order of execution also makes the component easier to reason about.


I always have my custom methods follow the lifecycle methods and be prefixed with an underscore to make them easier to identify. I’ll usually also group these by utility (parsers, event handlers, etc).


I like the render method to always be last. The render method is a mandatory lifecycle method and it’s almost always the function I need to find first when I open a file. Consequently, it’s pragmatic to have it in a consistent location across all of my components.


In general, my mixins will follow the same conventions as regular components.


Always set propTypes for validation and self-documentation


I always use propTypes to provide validation for each prop the component will receive. Furthermore, this also provides a self-documenting reference for how the component should be used, and what props it needs to be passed.




propTypes: {
arrayProp: React.PropTypes.array,
boolProp: React.PropTypes.bool,
funcProp: React.PropTypes.func,
numProp: React.PropTypes.number,
objProp: React.PropTypes.object,
stringProp: React.PropTypes.string,
}


JSX


Let’s face it, JSX can look pretty ugly at times and is one of the more common reasons developers are put off by React. However, by following a few general guidelines for handling JSX in components, it’s far more readable and not such an eyesore.


Multi-line JSX


No matter how few elements are being returned, I choose to write any JSX which contains nested elements across multiple lines with indentation to enhance readability, i.e:




return (
<div>
<ComponentOne />
<ComponentTwo />
</div>
);


Rather than…




return (<div><ComponentOne /><ComponentTwo /></div>);


Furthermore, while the parenthesis are not technically required with a single line JSX statement, I still use them for the sake of consistency (and because unrestrained elements floating about in my JS makes my left eye twitch uncontrollably).


Conditional JSX


When I have conditional elements that needs to be returned depending on state, props, or another condition, I declare an empty variable at the top of the render function and only populate it with JSX if the condition is met. When the variable is returned in the render method return statement, it’ll either render the conditional elements, or nothing at all.




var optionalElement;

if (this.props.condition) {
optionalElement = (<div> … </div>);
}

return (
<div>

{optionalElement}

</div>
);


In-line list iteration


Where possible, I like to iterate over lists of data in-line in the returned JSX unless its internal logic is sufficiently complex enough to warrant moving outside of the return statement and populating an array for rendering.




return (
<div>
{this.props.list.map(function(data, i) {
return (<Component data={data} key={i} />)
})}
</div>
);


Indentation and new line for component attributes


When there are enough attributes on a component that displaying them inline becomes untidy (usually 3 or more), I always display them on multiple lines and indent each one. i.e.




<Component
attribute={...}
anotherAttribute={...}
attributeThree={...}

/>


Rather than…




<Component attribute={...} anotherAttribute={...} attributeThree={...} />


Conclusion


These guidelines are by no means authoritative or exhaustive, but I feel they are a good starting point for organising and standardising React components and some of the more common use cases I encounter.


Hopefully these guidelines provide a useful starting point for organising your React components. Be sure to leave a comment if you have a question!


An opinionated guide to React.js best practices and conventions is a post from Web Design Weekly.




by John Cobb via Web Design Weekly

1 comment: