A mostly reasonable approach to React and JSX
- Basic Rules
- Method Ordering
render
functions- Observers and Handlers
React.createClass
vs Pure Components- Default Props
- Naming
- Spacing
- Props
- Alignment
- Tags
- Methods
isMounted
- Only include one React component per file.
- However, multiple Stateless, or Pure, Components are allowed per file. eslint rule:
react/no-multi-comp
.
- However, multiple Stateless, or Pure, Components are allowed per file. eslint rule:
- Always use JSX syntax.
All methods within your componenet should be ordered using the following list:
mixins
getDefaultProps
getInitialState
- Lifecycle Methods, eg.
componentWillMount
,componentDidMount
- Event Handlers like
handleSubmitClick()
orhandleChangeDescription()
- Getter methods for
render*
functions likegetSelectReason()
orgetFooterContent()
- Additional render methods like
renderNavigation()
orrenderProfilePicture()
render
- The logic within your
render
function should be kept at a minimum. If there is any looping, or complex conditions, it should be broken out into it's ownrender*
method.
// bad
var Foo = React.createClass({
render : function() {
return <ul className="items">
{_.map(this.props.items, (item) => {
return <li key={item.id}>{item.text}</li>
})}
</ul>;
}
});
// good
var Foo = React.createClass({
renderItems : function(){
return _.map(this.props.items, (item) => {
return <li key={item.id}>{item.text}</li>
})
},
render : function() {
return <ul className="items">
{this.renderItems()}
</ul>;
}
});
- Any prop passed to a component that is a function meant to be an "observer" should be prefixed by
on*
, eg.onChange
,onSubmit
,onUserSelect
// bad
<Foo click={this.handler} whenUserSubmits={this.handleSubmit} />
// good
<Foo onClick={this.handler} onUserSubmit={this.handleSubmit} />
- Any function within a function that reacts to external changes should be prefixed with
handle*
, eg.handleKeyPress
,handleUserSelect
// bad
var Foo = React.createClass({
onClick : function(){
/* ... */
},
render : function() {
return <button onClick={this.onClick}>Click me!</button>;
}
});
// good
var Foo = React.createClass({
handleClick : function(){
/* ... */
},
render : function() {
return <button onClick={this.handleClick}>Click me!</button>;
}
});
- It's common that a
handle*
function may just call an observer prop. This is fine, as often additional logic or logging will be added later.
// bad
var Foo = React.createClass({
getDefaultProps : function(){
return {
onClick : function(){}
}
},
render : function() {
return <button onClick={this.props.onClick}>Click me!</button>;
}
});
// good
var Foo = React.createClass({
getDefaultProps : function(){
return {
onClick : function(){}
}
},
handleClick : function(){
this.props.onClick();
},
render : function() {
return <button onClick={this.handleClick}>Click me!</button>;
}
});
- Use the
createClass
syntax for creating components
// good
var Listing = React.createClass({
// ...
render : function() {
return <div>{this.state.hello}</div>;
}
}
- If your componenet does not use state of refs, use function notation instead.
// bad
var Listing = React.createClass({
render : function() {
return <div>{this.props.hello}</div>;
}
})
// good
var Listing = function({ hello }){
return <div>{hello}</div>;
}
- If your component is expecting props, they should be defined within the
getDefaultProps
Why not
propTypes
? You can use Prop Validation, but our preferred method is prop defaulting. Validation tends to be more strict and less backwards compatible when working with shared components.
// bad
var Foo = React.createClass({ /* ... */ });
<Foo unexpectedProp="Neat!" />
// good
var Foo = React.createClass({
getDefaultProps : function(){
return {
unexpectedProp : ""
}
}
/* ... */
});
- Especially make sure to stub out any handlers with noop functions
// good
var Foo = React.createClass({
getDefaultProps : function(){
return {
onChange : function(){}
}
}
});
- Extensions: Use
.jsx
extension for React components. - Filename: Use camelCase for filenames. E.g.,
reservationCard.jsx
. - Reference Naming: Use PascalCase for React components.
// bad
var reservationCard = require('./ReservationCard.jsx');
// good
var ReservationCard = require('./reservationCard.jsx');
- Component Naming: Use the filename as the component name. For example,
reservationCard.jsx
should have a reference name ofReservationCard
.
- Always include a single space in your self-closing tag.
// bad
<Foo/>
// very bad
<Foo />
// bad
<Foo
/>
// good
<Foo />
- Always use camelCase for prop names.
// bad
<Foo
UserName="hello"
phone_number={12345678}
/>
// good
<Foo
userName="hello"
phoneNumber={12345678}
/>
// bad
render() {
return <MyComponent
className="long body" foo="bar">
<MyChild />
</MyComponent>;
}
// good
render() {
return <MyComponent className="long body" foo="bar">
<MyChild />
</MyComponent>
}
// good, when single line
render() {
const body = <div>hello</div>;
return <MyComponent>{body}</MyComponent>;
}
- Always self-close tags that have no children.
// bad
<Foo className="stuff"></Foo>
// good
<Foo className="stuff" />
- Do not use underscore prefix for internal methods of a React component.
// bad
React.createClass({
_onClickSubmit : function() {
// do stuff
},
// other stuff
});
// good
React.createClass({
onClickSubmit : function() {
// do stuff
}
// other stuff
}
- Do not use
isMounted
.
Why?
isMounted
is an anti-pattern, is not available when using ES6 classes, and is on its way to being officially deprecated.