- Only include one React component per file.
- Always use JSX syntax.
- Do not use
React.createElementunless you're initializing the app from a file that is not JSX.
- File- and component name need to be identical.
- Use PascalCase naming convention for filename as well as component name, e.g. GlobalHeader.js
// Bad
// Filename: foo.js
class Foo extends React.Component {}
export default Foo;
// Good
// Filename: Foo.js
class Foo extends React.Component {}
export default Foo;- Ordering for class extends React.Component:
- constructor
- optional static methods
- getChildContext
- componentWillMount
- componentDidMount
- componentWillReceiveProps
- shouldComponentUpdate
- componentWillUpdate
- componentDidUpdate
- componentWillUnmount
- clickHandlers or eventHandlers like onClickSubmit() or onChangeDescription()
- getter methods for render like getSelectReason() or getFooterContent()
- Optional render methods like renderNavigation() or renderProfilePicture()
- render
- How to define propTypes, defaultProps, contextTypes, etc...
import React, { Component, PropTypes } from 'react';
const propTypes = {
id: PropTypes.number.isRequired,
url: PropTypes.string.isRequired,
text: PropTypes.string,
};
const defaultProps = {
text: 'Hello World',
};
export default class Link extends Component {
static methodsAreOk() {
return true;
}
render() {
return <a href={this.props.url} data-id={this.props.id}>{this.props.text}</a>
}
}
Link.propTypes = propTypes;
Link.defaultProps = defaultProps;- Follow these alignment styles for JSX syntax
// bad
<Foo superLongParam="bar"
anotherSuperLongParam="baz" />
// good
<Foo
superLongParam="bar"
anotherSuperLongParam="baz"
/>
// if props fit in one line then keep it on the same line
<Foo bar="bar" />
// children get indented normally
<Foo
superLongParam="bar"
anotherSuperLongParam="baz"
>
<Spazz />
</Foo>- Always use double quotes (
") for JSX attributes, but single quotes for all other JS.
// bad
<Foo bar='bar' />
// good
<Foo bar="bar" />
// bad
<Foo style={{ left: "20px" }} />
// good
<Foo style={{ left: '20px' }} />
## Props
- Always use camelCase for prop names.
```javascript
// bad
<Foo
UserName="hello"
phone_number={12345678}
/>
// good
<Foo
userName="hello"
phoneNumber={12345678}
/>- Always self-close tags that have no children.
// bad
<Foo className="stuff"></Foo>
// good
<Foo className="stuff" />- If your component has multi-line properties, close its tag on a new line.
// bad
<Foo
bar="bar"
baz="baz" />
// good
<Foo
bar="bar"
baz="baz"
/>For stateless components use the function syntax, introduced in React 0.14.
// Using an ES2015 (ES6) arrow function:
var Aquarium = (props) => {
var fish = getFish(props.species);
return <Tank>{fish}</Tank>;
};
// Or with destructuring and an implicit return, simply:
var Aquarium = ({species}) => (
<Tank>
{getFish(species)}
</Tank>
);
// Then use: <Aquarium species="rainbowfish" />- Setting propTypes declarations is mandatory
- Group them into required/none-required
- Alphabetically sort each group
- Separate them by a new line
static propTypes = {
blank: React.PropTypes.bool.isRequired,
block: React.PropTypes.bool.isRequired,
size: React.PropTypes.string.isRequired,
to: React.PropTypes.string.isRequired,
disabled: React.PropTypes.bool,
};Prefix all none React methods within a component with an underscore.
class Foo extends React.Component {
componentDidMount() {
this._update();
}
_update() {
// e.g. update position
}
render() {
return (
<div>foo</div>
);
}
} In the exception that you do not want to place a component wide variables on the state, you have to prefix it with an underscore.
class Foo extends React.Component {
componentDidMount() {
this._el = React.FindDOMNode(this.refs.foo);
}
render() {
return (
<div>foo</div>
);
}
} - Name methods using
'_handle' + triggering event, e.g._handleClick - Bind handler using the ES6 arrow syntax, so inside the callback it has always the right context
class Foo extends React.Component {
_handleClick = (e) => {
this.setState(
{
clicked: true
}
);
}
render() {
return (
<button onClick={this._handleClick}>Submit</button>
);
}
}// CommentListContainer.js
class CommentListContainer extends React.Component {
constructor() {
super();
this.state = { comments: [] }
}
componentDidMount() {
$.ajax({
url: "/my-comments.json",
dataType: 'json',
success: function(comments) {
this.setState({comments: comments});
}.bind(this)
});
}
render() {
return <CommentList comments={this.state.comments} />;
}
}
// CommentList.js
class CommentList extends React.Component {
constructor(props) {
super(props);
}
_renderComment({body, author}) {
return <li>{body}—{author}</li>;
}
render() {
return <ul> {this.props.comments.map(_renderComment)} </ul>;
}
}Source: https://medium.com/@learnreact/container-components-c0e67432e005
render() {
return (
<Foo>
<Bar />
</Foo>
);
}When rendering a list of components from an array, do it inline if it makes sense. If the map function is too long or complicated, consider extracting it out into its own method on the component class.
render() {
return (
<ul>
{this.state.fooList.map(fooItem => <FooItem>{fooItem}</FooItem>)}
</ul>
);
}<input
type="text"
value={this.state.foo}
onChange={this._handleInputChange.bind(this, 'foo')}
/>Static properties should be set in the SCSS, dynamic ones in JS.
.Foo {
background-color: #ff0;
}class Foo extends React.Component {
render() {
const styles = {
'transform': 'translateX(' + this.state.position + ' + px)'
};
return (
<div className="Foo" styles={classes}>Foo Header</div>
)
};
}Use the classnames node module for setting CSS classes on an element.
import React from 'react';
import classnames from 'classnames';
class Foo extends React.Component {
render() {
const classes = classnames('FooHeader', {
'is-fixed': this.state.fixed,
'is-visible': this.state.visible
});
return (
<div className={classes}>Foo Header</div>
)
};
}http://facebook.github.io/react/tips/dom-event-listeners.html
https://github.com/reactjs/react-static-container
https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750