/eslint-config-defaults

ESLint Rules for JavaScript/React Projects.

Primary LanguageJavaScript

eslint-config-defaults

Shareable ESLint Configs. Heavily inspired by Colby Dauphinais and Airbnb.

React Rules #### Basic Rules * Only include one React component per file [[rule]](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-multi-comp.md). * Always use JSX syntax.

Class vs React.createClass vs stateless

  • If you have internal state and/or refs prefer class extends React.Component or class extends React.PureComponent over createReactClass.

rules: react/prefer-es6-class and react/prefer-stateless-function

Naming

  • Extensions: use .jsx extension for React components
  • Filename: Use PascalCase for filenames, e.g. ReservationCard.jsx
  • Reference Naming: Use PascalCase for React components and camelCase for their instances.

rules: react/jsx-pascal-case

// bad
import reservationCard from './ReservationCard';

// good
import ReservationCard from './ReservationCard';

// bad
const ReservationItem = <ReservationCard />;

// good
const reservationItem = <ReservationCard />;

Alignment

  • Follow these alignment styles for JSX syntax.
    • JSX should have 2 spaces indentation
    • Props should have 2 spaces indentation

rules: react/jsx-closing-bracket-location and react/jsx-closing-tag-location and jsx-indent and react/jsx-indent-props

// 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"
>
  <Quux />
</Foo>

Spacing

  • Always include a single space before a self-closing tag, and no spaces after opening tags or closing slashes
// bad
<App/ >
<App/>
< App/ >

// good
<App />
  • Do not include multiple spaces in a row that are not used for indentation. These are usually mistakes.
// bad
if(foo   === "bar") {}

// good
if(foo === "bar") {}

rule: react/jsx-tag-spacing and no-multi-spaces

// bad jsx
<Hello name={ name } />
<Hello name={ name} />
<Hello name={name } />

// good jsx
<Hello name={name} />

// bad object literal
<Hello name={name} foo={ {bar: true, baz: true} } />

// good object literal
<Hello name={name} foo={{ bar: true, baz: true }} />
// bad
<Hello name = {name} />
<Hello name= {name} />
<Hello name ={name} />

// good
<Hello name={name} />

Props

Why? propTypes are a form of documentation, and providing defaultProps means the render of your code doesn't have to assume as much. In addition, it can mean that your code can omit certain type checks.

// bad
<Foo hidden />

// good
<Foo hidden={true} />
  • Always include an alt prop on <img> tags. If the image is presentational, alt can be an empty string or the <img> must have role=presentational. eslint: jsx-a11y/alt-text
// bad
<img src="hello.js" />

// good
<img src="hello.jpg" alt="Me waving hello" />

// good
<img src="hello.jpg" alt="" />

// good
<img src="hello.jpg" role="presentation" />
  • Do not use PropTypes.any, PropTypes.array, or PropTypes.object. Prefer specificity of definition. eslint: react/forbid-prop-types
// bad
static propTypes = {
  a: PropTypes.any,
  b: PropTypes.array,
  c: PropTypes.object,
}

// good
static propTypes = {
  a: PropTypes.number,
  b: PropTypes.arrayOf(
    PropTypes.string,
  ),
  c: PropTypes.shape({
    title: PropTypes.string,
    body: PropTypes.string,
  })
}
  • Avoid using an array index as key prop, prefer a unique id (Why?)

The key is used by React to identify which items have changed, are added, or are removed and should be stable. It is a bad idea to use the array index as your key since it doesn't uniquely identify your elments. In cases where the array is sorted or an element is added to the beginning of the array, the index will be changed even though th element representing that index may be the same. This results in unecessary renders. eslint: react/no-array-index-key

You can disable this rule when there is nothing unique about the items, for example, you are breaking an array down into chunks.

// bad
{todos.map((todo, index) =>
  <Todo
    {...todo}
    key={index}
  />
)}

// good
{todos.map(todo => {
  <Todo
    {...todo}
    key={todo.id}
  />
})}
  • Don't forget a key property if it is required, namely for array literals or arrow function expressions. eslint: react/jsx-key

  • Prevent missing props validation in a React component definition. eslint: react/prop-types

Why? PropTypes improve the reusability of your component by validating the received data. It can warn other developers if they make a mistake while reusing the component with improper data.

// bad
class Hello extends PureComponent {
  render() {
    return <div>Hello {this.props.name}</div>;
  }
}

// good
class Hello extends PureComponent {
  static propTypes = {
    name: PropTypes.string,
  }

  render() {
    return <div>Hello {this.props.name}</div>
  }
}
  • Enforce propType declarations to be sorted in alphabetical order. This makes it easier to find the necessary declarations. eslint: react/sort-prop-types
// bad
static propTypes = {
  z: PropTypes.string,
  c: PropTypes.string,
  a: PropTypes.string,
}

// good
static propTypes = {
  a: PropTypes.string,
  b: PropTypes.string,
  z: PropTypes.string,
}
// bad
<Hello name="John" name="Doe" />

// good
<Hello firstName="John" lastName="Doe" />

Refs

Providing a string identifier as a ref is considered legacy by the official documentation.

// bad
<Foo ref="myRef" />

// good
<Foo
  ref={(ref) => { this.myRef = ref; }}
/>

Parentheses

// bad
render() {
  return  <MyComponent className="long body" foo="bar">
            <MyChild />
          </MyComponent>;
}

// good
render() {
  return (
    <MyComponent className="long body" foo="bar">
      <MyChild />
    </MyComponent>;
  );
}

// good when one line
render() {
  const body = <div>hello</div>;
  return <MyComponent>{body}</MyComponent>;
}

Tags

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

// good
<Foo className="stuff" />
// bad
<Foo
  bar="bar"
  baz="baz" />

// good
<Foo
  bar="bar"
  baz="baz"
/>

Methods

  • Bind event handlers for the render method in the constructor. eslint: react/jsx-no-bind

Why? A bind call in the render path creates a brand new function on every render.

// bad
class extends React.Component {
  onClickDiv() {
    // do stuff
  }

  render() {
    return <div onClick={this.onClickDiv.bind(this)} />;
  }
}

// good
class extends React.Component {
  constructor(props) {
    super(props);

    this.onClickDiv = this.onClickDiv.bind(this);
  }

  onClickDiv() {
    // do stuff
  }

  render() {
    return <div onClick={this.onClickDiv} />;
  }
}
// bad
render() {
  (<div />)
}

// good
render() {
  return <div />;
}

Ordering

  1. optional static methods
  2. constructor
  3. getChildContext
  4. 1componentWillMount1
  5. componentDidMount
  6. componentWillReceiveProps
  7. shouldComponentUpdate
  8. componentWillUpdate
  9. componentDidUpdate
  10. componentWillUnmount
  11. clickHandlers or eventHandlers, like onClickSubmit() or onChangeDescription()
  12. getter methods for render, like getSelectReason() or getFooterContent()
  13. optional render methods like renderNavigation() or renderProfilePicture()
  14. render

isMounted

Why? isMounted is an anti-pattern, is not available when using ES6 classes, and is on its way to being officially deprecated.

Prevent Usage of Deprecated Methods

Several methods are deprecated between React versions. eslint: react/no-deprecated

The following methods are considered deprecated:

React.render(<MyComponent />, root);
React.unmountComponentAtNode(root);
React.findDomNode(this.refs.foo);
React.renderToString(<MyComponent />);
React.renderToStaticMarkup(<MyComponent />);
React.createClass({ /* Class object */ });
const propTypes = {
  foo: PropTypes.bar
};

import React, { PropTypes } from react;

Lifecycle Methods

Why? Updating the state after the component mount will trigger a second render() call and lead to property/layout thrashing.

State

  • Never mutate this.state directly, as calling setState() afterwards may replace the mutations you made. Treat this.state as if it were immutable. The only place that's acceptable to assign this.state is in a ES6 class component constructor. eslint: react/no-direct-mutation-state
// bad
this.state.name = this.props.name.toUpperCase();

// good
this.setState({
  name: this.props.name.toUpperCase();
});

JSX Rules

// bad
// filename: MyComponent.js
function MyComponent() {
  return <div />;
}

// good
// filename MyComponent.jsx
function MyComponent() {
  return <div />;
}
// bad
<Hello personal={true}
  foo="bar"
/>
<Hello foo={{

}} />

// good
<Hello personal={true} />
<Hello
  personal={true}
  foo="bar"
/>
  • Ensure that all component prop methods used to handle events are named correctly. The method's prop should be onEvent and the handler should be handleEvent. eslint: react/jsx-handler-names
// bad
<MyComponent handleChange={this.handleChange} />
<MyComponent onChange={this.componentChanged} />

// good
<MyComponent onChange={this.handleChange} />
<MyComponent onChange={this.props.onFoo} />

Misc

  • Prevent usage of unknown DOM properties. In JSX all DOM properties and attributes should be camelCased to be consistent with standard JavaScript style. This can be a possible source of errors. eslint react/no-unknown-property
import React from 'react';
// bad
const Hello = <div class="hello">Hello World</div>

// good
const Hello = <div className="hello">Hello World</div>
  • Prevent missing React when using JSX. When using JSX, <a /> expands to React.createElement("a"). Therefore the React variable must be in scope. If you are using JSX this rule will check the designated variable and not the React one. eslint: react/react-in-jsx-scope
// bad
const Hello = <div>Hello {this.props.name}</div>;

// good
import React from 'react';
const Hello = <div>Hello {this.props.name}</div>;
// bad
const Hello = <a target="_blank" href="http://example.com" />

// good
const Hello = <p target="_blank" /></p>
const Hello = <a target="_blank" rel="noopener noreferrer" href="http://example.com" />
const Hello = <a target="_blank" href="relative/path/in/the/host" />
const Hello = <a target="_blank" href="/absolute/path/in/the/host" />
  • Do not use string literals in JSX. This prevents any odd artifacts of highlighters if your unwrapped string contains an enclosing character like ' in contradictions and enforces consistency. eslint: react/jsx-no-literals
// bad
const Hello = <div>Hello</div>;

// good
const Hello = <div>{"Hello"}</div>;