Skip to content

crowdanalyzer/eslint-react

Repository files navigation

CrowdAnalyzer React/JSX Style Guide

CircleCI

  1. Basic Rules
  2. Classes vs Stateless
  3. Naming
  4. Alignment
  5. Spacing
  6. Props
  7. Refs
  8. Ordering
  9. State
  10. Styles

1.1 Only include one React component per file. (no-multi-comp)

// bad
var Hello = createReactClass({
  render: function() {
    return <div>Hello {this.props.name}</div>;
  }
});

var HelloJohn = createReactClass({
  render: function () {  
    return <Hello name = "John" /> ;
  }
});

// good
var Hello = require('./components/Hello');
var HelloJohn = createReactClass({
  render: function() {
    return <Hello name="John" />;
  }
});

1.2 Always use JSX syntax.

1.3 Do not use React.createElement unless you’re initializing the app from a file that is not JSX.

1.4 Always use a displayName for components when exporting them so they can be easily identified in react dev tools. this can be easily done by the transpiler as long you export the component correctly. see examples below

// bad
export default () => {
  return <button />;
}

// good
// Named export (declaration)
export function Button() {
  return <button />;
}

// Named export (arrow)
export const Button = () => {
  return <button />;
}

// Default export (declaration)
export default function Button() {
  return <button />;
}

// Default export (arrow)
const Button = () => {
  return <button />;
}
export default Button;

Back to Top

2.1 If you have internal state and/or refs, prefer class extends React.Component over React.createClass. if you don't have state or refs, prefer normal functions (not arrow functions) over classes (prefer-es6-class) & (prefer-stateless-function)

// bad
const Listing = React.createClass({
  render() {
    return <div>{this.state.hello}</div>;
  }
});

const Listing = ({ hello }) => (
  <div>{hello}</div>
);

// good
class Listing extends React.Component {
  render() {
    return <div>{this.state.hello}</div>;
  }
}

function Listing({ hello }) {
  return <div>{hello}</div>;
}

Back to Top

3.1 Extensions: Use .jsx extension for React components. If you use TypeScript, you will use .tsx extension by default. (jsx-filename-extension)

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

// good
// filename: MyComponent.jsx
function MyComponent() {
  return <div />;
}

// filename: MyComponent.tsx
const MyComponent: React.FC = () {
  return <div />;
}

3.2 Filename: Use PascalCase for filenames. E.g., ReservationCard.jsx. (jsx-pascal-case)

3.3 Reference Naming: Use PascalCase for React components and camelCase for their instances. (jsx-pascal-case)

// bad
import reservationCard from './ReservationCard';
const ReservationItem = <ReservationCard />;

// good
import ReservationCard from './ReservationCard';
const reservationItem = <ReservationCard />;

3.4 Component Naming: Use the filename as the component name. For example, ReservationCard.jsx should have a reference name of ReservationCard. However, for root components of a directory, use index.jsx as the filename and use the directory name as the component name:

// bad
import Footer from './Footer/Footer';
import Footer from './Footer/index';

// good
import Footer from './Footer';

Back to Top

4.1 Avoid extra closing tags for components without children (self-closing-comp)

// bad
var HelloJohn = <Hello name="John"></Hello>;
    
// good
var contentContainer = <div className="content"></div>;
var intentionalSpace = <div>{' '}</div>;
var HelloJohn = <Hello name="John" />;
var Profile = <Hello name="John"><img src="picture.png" /></Hello>;
var HelloSpace = <Hello>{' '}</Hello>;

4.2 Enforce the closing bracket location for JSX multiline elements, the closing bracket should be placed after props (closing-bracket-location)

// bad 
var x = function() {
  return <Say
    firstName="John"
    lastName="Smith"
         >
    Hello
         </Say>;
};

// good
<Hello
  firstName="John"
  lastName="Smith" />;

<Say
  firstName="John"
  lastName="Smith">
  Hello
</Say>;

4.3 The closing tag location should be on the same line if it is one line expression, while it should be aligned with the opening tag if it is multiline expression. (jsx-closing-tag-location)

// bad
<Hello>
  marklar
  </Hello>
<Hello>
  marklar</Hello>
    
// good
<Hello>
  marklar
</Hello>
<Hello>marklar</Hello>

4.4 Ensure correct position of the first property. (jsx-first-prop-new-line)

// bad
<Hello foo={{
    }}
    bar />
    
// good
<Hello foo={{}} />
<Hello
  foo={{}}
  bar
/>

4.5 Limit the maximum of props on a single line can improve readability, If it is multiline expression, then it’s one property per line (jsx-max-props-per-line)

// bad
<Hello 
firstName="John" lastName="Smith" />
  
// good
<Hello firstName="John" lastName="Smith" />
<Hello
firstName="John"
lastName="Smith"
/>

4.6 Limit every line in JSX to one expression each. (jsx-one-expression-per-line)

// bad
<App><Hello /><Hello2 /></App>

// good
<App>Hello</App>
<App>{"Hello"}</App>
<App>
  <Hello />
  <Hello2 />
</App>

4.7 Avoid unnecessary curly braces in JSX props and / or children. (jsx-curly-brace-presence)

// bad
<App>{'Hello world'}</App>;
<App prop={'Hello world'} attr={"foo"} />;

// good
<App>Hello world</App>;
<App prop="Hello world" attr="foo" />;

Back to Top

5.1 Avoid using extra spaces, React removes extraneous new lines between elements when possible, it is possible to end up with inline elements that are not rendered with spaces between them and adjacent text. This is often indicative of an error, so this rule attempts to detect.(jsx-child-element-spacing)

// bad
<div>
  Here is a
  <a>link</a>
</div>

<div>
  <b>This text</b>
  is bold
</div>

// good
<div>
  Spacing is
  {' '}
  <a>explicit</a>
</div>
<div>
  Lack of spacing is{/*
  */}<a>explicit</a>
</div>

5.2 Avoid spaces inside of curly braces in JSX attributes and expressions or around equal signs in JSX attributes (jsx-curly-spacing) & (jsx-equals-spacing)

// bad
<Hello name={ firstname } />;
<Hello name={ firstname} />;
<Hello name={firstname } />;
<Hello name={
  firstname
} />;
<Hello name = {firstname} />;
<Hello name ={firstname} />;
<Hello name= {firstname} />;

// good
<Hello name={firstname} />;
<Hello name={{ firstname: 'John', lastname: 'Doe' }} />;
<Hello>{firstname}</Hello>;
<Hello>{ firstname }</Hello>;
<Hello>{
  firstname
}</Hello>;
<Hello name />;
<Hello {...props} />;

5.3 Enforce consistent indentation style. 2 spaces.(jsx-indent) & (jsx-indent-props) & (indent)

// bad
<App>
    <Hello />
</App>

// bad
<App>
<Hello />
</App>

// bad
{
      hello: "world"
}

// good
<App>
  <Hello />
</App>

// good
{
  hello: "world"
}

5.4 Avoid multiple spaces between inline JSX props. (jsx-props-no-multi-spaces)

// bad
<App  spacy />
<App too  spacy />

// good
<App cozy={true} />
<App very={true} cozy={true}/>

5.5 Avoid spaces after the opening bracket, before the closing bracket and between the angle bracket and slash of JSX self-closing elements. Leave space before the closing bracket of self-closing elements. (jsx-tag-spacing)

// bad
<Hello firstname="John"/>
<Provider>< /Provider>
< Hello firstName="John"/>

// good
<Hello firstName="John" />
<Provider></Provider>

Back to Top

6.1 Prevent missing props validation in a React component definition. (prop-types)

// bad
var Hello = createReactClass({
  render: function() {
    return <div>Hello {this.props.name}</div>;
  }
});

// good
var Hello = createReactClass({
  propTypes: {
    name: PropTypes.string.isRequired,
  },
  render: function() {
    return <div>Hello {this.props.name}</div>;
  },
});

6.2 Enforce consistent usage of destructuring assignment of props, state, and context. (destructuring-assignment)

// bad
const MyComponent = (props) => {
  return (<div id={props.id} />)
};

// good 
const MyComponent = ({id}) => {
  return (<div id={id} />)
};

6.3 Prevents passing of props that add lots of complexity (className, style) to Components. This rule only applies to Components (e.g. <Foo />) and not DOM nodes (e.g. <div />). (forbid-component-props)

// bad
<Hello className='foo' />
<Hello style={{color: 'red'}} />

// good
<Hello name='Joe' />
<div className='foo' />

6.4 Avoid using an array index as key prop, prefer a stable ID. (no-array-index-key)

// bad
React.Children.map(this.props.children, (child, index) => (
  React.cloneElement(child, { key: index })
))
Children.forEach(this.props.children, (child, index) => (
  React.cloneElement(child, { key: index })
))

// good
React.Children.map(this.props.children, (child, index) => (
  React.cloneElement(child, { key: child.id })
))
Children.forEach(this.props.children, (child, index) => (
  React.cloneElement(child, { key: child.id })
))

6.5 Prevent passing of children as props, Children should always be actual children, not passed in as a prop. When using JSX, the children should be nested between the opening and closing tags. When not using JSX, the children should be passed as additional arguments to React.createElement. (no-children-prop)

// bad
<div children='Children' />

<MyComponent children={<AnotherComponent />} />
<MyComponent children={['Child 1', 'Child 2']} />

React.createElement("div", { children: 'Children' })

// good
<div>Children</div>
<MyComponent>Children</MyComponent>

<MyComponent>
  <span>Child 1</span>
  <span>Child 2</span>
</MyComponent>

React.createElement("div", {}, 'Children')
React.createElement("div", 'Child 1', 'Child 2')

6.6 Ensure that the value of the prop style be an object or a variable that is an object. (style-prop-object)

// bad
<div style="color: 'red'" />
<div style={true} />
<Hello style={true} />
const styles = true;
<div style={styles} />

// good
<div style={{ color: "red" }} />
<Hello style={{ color: "red" }} />
const styles = { color: "red" };
<div style={styles} />

6.7 Ensures that any component or prop methods used to handle events are correctly prefixed. (jsx-handler-names)

// bad
<MyComponent handleChange={this.handleChange} />
<MyComponent onChange={this.componentChanged} />

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

6.8 Avoid duplicate props which can cause unexpected behaviour in your application. (jsx-no-duplicate-props)

// bad
<Hello name="John" name="John" />;

// good
<Hello firstname="John" lastname="Doe" />;

Back to Top

7.1 Currently, two ways are supported by React to refer to components. The first way, providing a string identifier, is now considered legacy in the official documentation. The documentation now prefers a second method -- referring to components by setting a property on the this object in the reference callback. (no-string-refs)

// bad
var Hello = createReactClass({
  render: function() {
    return <div ref="hello">Hello, world.</div>;
  }
});

// good
var Hello = createReactClass({
  componentDidMount: function() {
    var component = this.hello;
  },
  render() {
    return <div ref={(c) => { this.hello = c; }}>Hello, world.</div>;
  }
});

7.2 When creating a JSX element that has an a tag, it is often desired to have the link open in a new tab using the target='_blank' attribute. Using this attribute unaccompanied by rel='noreferrer noopener', however, is a severe security vulnerability (see here for more details) This rules requires that you accompany target='_blank' attributes with rel='noreferrer noopener'. (jsx-no-target-blank)

// bad
var Hello = <a target='_blank' href="http://example.com/"></a>
var Hello = <a target='_blank' href={ dynamicLink }></a>

//good
var Hello = <p target='_blank'></p>
var Hello = <a target='_blank' rel='noopener noreferrer' href="http://example.com"></a>
var Hello = <a target='_blank' href="relative/path/in/the/host"></a>
var Hello = <a target='_blank' href="/absolute/path/in/the/host"></a>
var Hello = <a></a>

Back to Top

8.1 When creating React components it is more convenient to always follow the same organisation for method order to help you easily find lifecycle methods, event handlers, etc. (sort-comp) The current Recommended Order For class components 1- Constructor 2- life cycle Methods e.g., componentDidMount, etc. 3- Static Methods e.g., handleSubmit, etc. 4- render function

// bad
var Hello = createReactClass({
  render: function() {
    return <div>Hello</div>;
  },
  displayName : 'Hello'
});

// good
var Hello = createReactClass({
  displayName : 'Hello',
  render: function() {
    return <div>Hello</div>;
  }
});

Back to Top

9.1 Prevent usage of this.state inside setState calls. Such usage of this.state might result in errors when two state calls are called in batch and thus referencing old state and not the current state. (no-access-state-in-setstate)

// bad 
function increment() {
  this.setState({value: this.state.value + 1});
}

// good
function increment() {
  this.setState(prevState => ({ value: prevState.value + 1}));
}

9.2 Avoid updating the state after a component mount or component update as it will trigger a second render() call and can lead to property/layout thrashing. (no-will-update-set-state) & (no-did-mount-set-state)

// bad
var Hello = createReactClass({
  componentDidMount: function() {
    this.setState({
      name: this.props.name.toUpperCase()
    });
  },
  render: function() {
    return <div>Hello {this.state.name}</div>;
  }
});

var Hello = createReactClass({
  componentDidUpdate: function() {
    this.setState({
      name: this.props.name.toUpperCase()
    });
  },
  render: function() {
    return <div>Hello {this.state.name}</div>;
  }
});

// good
var Hello = createReactClass({
  componentDidMount: function() {
    this.onMount(function callback(newName) {
      this.setState({
        name: newName
      });
    });
  },
  render: function() {
    return <div>Hello {this.state.name}</div>;
  }
});

var Hello = createReactClass({
  componentDidUpdate: function() {
    this.props.onUpdate();
  },
  render: function() {
    return <div>Hello {this.props.name}</div>;
  }
});

9.3 NEVER mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable. (no-direct-mutation-state)

// bad
var Hello = createReactClass({
  componentDidMount: function() {
    this.state.name = this.props.name.toUpperCase();
  },
  render: function() {
    return <div>Hello {this.state.name}</div>;
  }
});

class Hello extends React.Component {
  constructor(props) {
    super(props)

    // Assign at instance creation time, not on a callback
    doSomethingAsync(() => {
      this.state = 'bad';
    });
  }
}
// good
var Hello = createReactClass({
  componentDidMount: function() {
    this.setState({
      name: this.props.name.toUpperCase();
    });
  },
  render: function() {
    return <div>Hello {this.state.name}</div>;
  }
});

class Hello extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      foo: 'bar',
    }
  }
}

9.4 Avoid updating the state during the componentWillUpdate step as it can lead to indeterminate component state and is not allowed. (no-will-update-set-state)

// bad
var Hello = createReactClass({
  componentWillUpdate: function() {
    this.setState({
      name: this.props.name.toUpperCase()
    });
  },
  render: function() {
    return <div>Hello {this.state.name}</div>;
  }
});

// good
var Hello = createReactClass({
  componentWillUpdate: function() {
    this.props.prepareHandler();
  },
  render: function() {
    return <div>Hello {this.props.name}</div>;
  }
});    

Back to Top

10.1 Always use double quotes (") for JSX attributes. (jsx-quotes)

// bad
<Foo bar='bar' />
<Foo style={{ left: '20px' }} />

// good
<Foo bar="bar" />
<Foo style={{ left: "20px" }} />

Back to Top

About

Crowd Analyzer React/JSX Style Guide

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •