Skip to content

Instantly share code, notes, and snippets.

@stolksdorf
Created April 12, 2016 15:38
Show Gist options
  • Save stolksdorf/25948be97d8dd18c237a666c1ec1172c to your computer and use it in GitHub Desktop.
Save stolksdorf/25948be97d8dd18c237a666c1ec1172c to your computer and use it in GitHub Desktop.
React Style Guide

React/JSX Style Guide (){

A mostly reasonable approach to React and JSX

Table of Contents

  1. Basic Rules
  2. Method Ordering
  3. render functions
  4. Observers and Handlers
  5. React.createClass vs Pure Components
  6. Default Props
  7. Naming
  8. Spacing
  9. Props
  10. Alignment
  11. Tags
  12. Methods
  13. isMounted

Basic Rules

Method Ordering

All methods within your componenet should be ordered using the following list:

  1. mixins
  2. getDefaultProps
  3. getInitialState
  4. Lifecycle Methods, eg. componentWillMount, componentDidMount
  5. Event Handlers like handleSubmitClick() or handleChangeDescription()
  6. Getter methods for render* functions like getSelectReason() or getFooterContent()
  7. Additional render methods like renderNavigation() or renderProfilePicture()
  8. render

render function

  • 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 own render* 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>;
		}
	});

Observers and Handlers

  • 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>;
		}
	});

React.createClass vs Pure Components

  • 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>;
	}

Default Props

  • 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(){}
			}
		}
	});

Naming

  • 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 of ReservationCard.

Spacing

  • Always include a single space in your self-closing tag.
	// bad
	<Foo/>

	// very bad
	<Foo                 />

	// bad
	<Foo
	 />

	// good
	<Foo />

Props

  • Always use camelCase for prop names.
	// bad
	<Foo
		UserName="hello"
		phone_number={12345678}
	/>

	// good
	<Foo
		userName="hello"
		phoneNumber={12345678}
	/>

Alignment

	// 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>;
	}

Tags

  • Always self-close tags that have no children.
	// bad
	<Foo className="stuff"></Foo>

	// good
	<Foo className="stuff" />

Methods

  • 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
	}

isMounted

  • 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.

};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment