A best practices style guide for managing sane react components. This guide assumes you are using Webpack + Babel + es6 syntax, but the guide's syntax and conventions should be able to be generally applied if you aren't. I highly encourage you to use some build system + es6 for building react components.
- Have only one component per file using '.js' file extension. no need to do '.jsx'
- Use PascalCase for naming React components and files.
// ES6 ... best practice
// Use es6 import syntax and destructor if you need to.
import React from 'react';
import AwesomeComponent from './AwesomeComponent'; //no need to put .js if it's a .js file. (use .js over .jsx for webpack/babel)
import {Route, DefaultRoute, NotFoundRoute} from 'react-router';
// ES5 ... bad practice
var React = require('react');
var Router = require('react-router');
var Route = Router.Route;
var DefaultRoute = Router.DefaultRoute;
var NotFoundRoute = Router.NotFoundRoute;
//<PeopleList />
// |
// V
var Person = React.createClass({
// Defaults and initialization properties at the top
propTypes: {},
getInitialState: function() {},
getDefaultProps: function() {},
// Life-cycle methods here
componentWillMount: function() {},
componentWillReceiveProps: function() {},
componentWillUnmount: function() {},
// Instance methods (any application logic should be refactored out into the Store)
someHelperMethod: function() {},
someOtherInstanceMethod: function() {},
dynamicCss: function() {},
// The most important method in a react class. Make sure to keep it simple as possible.
render : function() {},
// Actions handlers underneath render() prefixed with _
_addPoints: function() {}
})
-
- Don't pass props to state.
componentDidMount: function(){ this.setState({ people: this.props.people }) // BAD: usually a code smell if you're pass down props to state. }
- Note: replaceState effects entire state, setState merges with the current state.
this.setState({ isEditing: true }); ... (later) ... this.replaceState({ isActive: true }); // isEditing no longer part of current state this.setState({ isActive: true }); // isActive merges into current state
- Try to only use application data with ```Props``` not ```State```.
- Don't pass props to state.
-
###Comments
- Write a comment at the top of the component class if the component belongs to a parent component, especially if the parent component is passing in
props
.
- Write a comment at the top of the component class if the component belongs to a parent component, especially if the parent component is passing in
-
###Methods
-
Class instance methods should do one thing. (Single Responsibility Principle)
-
Don't change state in a child component without letting the parent component know. Deeply nested components are really hard and can be confusing at times if you use too much state and instead of using props data.
-
Use less state and more
this.props
in your render method. -
Learn about
.bind();
because you're most likely going to be using a scopedthis
in a function inside of a function.render: function(){ var editPositionState = function () { // this.props is undefined return this.props.stage.position === this.state.editPosition; }; var editPositionState = function () { // this.props works! return this.props.stage.position === this.state.editPosition; }.bind(this); // or you can do it the lame way and grab this.props // before a function and assign it to a variable. }
- or if your using a ES6 transpiler like Babeljs use arrow functions to keep the correct context.
render: function(){ var editPositionState = () => { // this.props works! return this.props.stage.position === this.state.editPosition; } }
-
Use multi-line jsx if a component has more than two properties.
<Component propertyOne={...} propertyTwo={...} propertyThree={...} … />
-
Don't get fancy with manipulating child DOM elements. Map over them and create child components instead.
// Good render: function() { var people = this.props.people.map(function (person) { if (person){ return ( <Person person = {person} handleUpdate = {this.handleUpdate} key = {person.id}/> ); } }, this); return ( <ul> {people} </ul> ) } //Better render: function() { return ( <ul> { this.props.people.map(function (person) { if (person){ return ( <Person person = {person} handleUpdate = {this.handleUpdate} key = {person.id}/> ); } }, this); } </ul> ) }
- If it's a simple iteration over an array, render out each of the elements in an array inside jsx.
- Don't use mixins.. thinking about composable components instead. Mixins will get deprecated
- Useful when you're creating dynamic css styles for your components and it can be fun!
- CSS should be unique for a component.
- Abstract your css into a class method if it's dynamic CSS.
- Throw in that class method of all your inline styles defined into
style={...}
cssStyles: function(){...}, render: function(){ return ( <div style={this.cssStyles()} css styles created in JS! </div> ) }
- Jest best practices...
- React dev console chrome extension
- react-rails gem (if you're using rails)
- an editor that supports vertical split screens for managing hiearchy and thinking about one-way data flow.
airbnb's react/jsx style guide
- TBA