Airbnb React/JSX Coding Specification

Keywords: Javascript React Attribute

Come from Chinese Coding Specification for Airbnb React/JSX

Airbnb React/JSX Coding Specification

One of the most reasonable React/JSX coding specifications

Content directory

  1. Basic norms

  2. Class vs React.createClass vs stateless

  3. name

  4. Declaration module

  5. Code alignment

  6. Single or double quotation marks

  7. Blank space

  8. attribute

  9. Refs reference

  10. brackets

  11. Label

  12. Function/Method

  13. Module life cycle

  14. isMounted

Basic Rules Basic Specification

  • Each file only writes one module.

  • JSX grammar is recommended.

  • Do not use React.createElement unless you initialize your app from a non-JSX file.

Create module

Class vs React.createClass vs stateless

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

// good
class Listing extends React.Component {
  // ...
  render() {
    return <div>{this.state.hello}</div>;
  }
}
If your module is stateless or does not refer to `refs', it is recommended to use normal functions (non-arrow functions) instead of classes:
// bad
class Listing extends React.Component {
  render() {
    return <div>{this.props.hello}</div>;
  }
}

// bad (relying on function name inference is discouraged)
const Listing = ({ hello }) => (
  <div>{hello}</div>
);

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

Naming

  • Extension: React module uses. jsx extension.
    - File name: File name is named after Pascal. For example, ReservationCard.jsx.

- Reference naming: The React module name is Pascal naming, and the instance is camel naming. react/jsx-pascal-case

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

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

// bad
const ReservationItem = <ReservationCard />;

// good
const reservationItem = <ReservationCard />;
  • Module Naming: Modules use the same name as the current file name. For example, ReservationCard.jsx should contain a module named ReservationCard. However, if the entire folder is a module, use index.js as the entry file, and then use index.js or folder name directly as the module name:

    // bad
    import Footer from './Footer/Footer';
    
    // bad
    import Footer from './Footer/index';
    
    // good
    import Footer from './Footer';
  • High-order module naming: For generating a new module, the module name displayName should be a combination of the high-order module name and the incoming module name. For example, the high-order module withFoo(), when passing in a Bar module, the generated module name displayName should be withFoo(Bar).

Why? A module's displayName may be used in developer tools or error messages, so having a value that clearly expresses this relationship can help us better understand what's happening in the module and better Debug.

// bad
export default function withFoo(WrappedComponent) {
  return function WithFoo(props) {
    return <WrappedComponent {...props} foo />;
  }
}

// good
export default function withFoo(WrappedComponent) {
  function WithFoo(props) {
    return <WrappedComponent {...props} foo />;
  }

  const wrappedComponentName = WrappedComponent.displayName
    || WrappedComponent.name
    || 'Component';

  WithFoo.displayName = `withFoo(${wrappedComponentName})`;
  return WithFoo;
}
  • Property naming: Avoid using DOM-related properties for other purposes.

Why? For attribute names such as style and className, we all default that they represent specific meanings, such as the style of the element and the name of the CSS class. Using these attributes to represent other meanings in your application will make your code harder to read, more difficult to maintain, and may cause bug s.

// bad
<MyComponent style="fancy" />

// good
<MyComponent variant="fancy" />

Declaration declaration module

  • Instead of using displayName to name React modules, use references to name modules, such as class names.

    // bad
    export default React.createClass({
      displayName: 'ReservationCard',
      // stuff goes here
    });
    
    // good
    export default class ReservationCard extends React.Component {
    }

Alignment code alignment

  • Follow the following JSX syntax indentation/format. eslint: react/jsx-closing-bracket-location

    // bad
    <Foo superLongParam="bar"
         anotherSuperLongParam="baz" />
    
    // good, if you have multiple line attributes, create a new line to close the label
    <Foo
      superLongParam="bar"
      anotherSuperLongParam="baz"
    />
    
    // If you can display it in one line, write it directly in one line
    <Foo bar="bar" />
    
    // Subelements are indented in a conventional way
    <Foo
      superLongParam="bar"
      anotherSuperLongParam="baz"
    >
      <Quux />
    </Foo>

Quotes Single or Double Quotes

  • Double quotation marks (") are always used for JSX attribute values, and single quotation marks ('). eslint: jsx-quotes

Why? HTML attributes also use double quotation marks, so JSX attributes follow this convention.

// bad
<Foo bar='bar' />

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

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

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

Spacing space

  • Always add a space before the auto-closing label. Normally, no line change is required. no-multi-spaces, react/jsx-space-before-closing

    // bad
    <Foo/>
    
    // very bad
    <Foo                 />
    
    // bad
    <Foo
     />
    
    // good
    <Foo />
  • Do not add spaces to both sides of the parentheses in JSX {} reference. react/jsx-curly-spacing

    // bad
    <Foo bar={ baz } />
    
    // good
    <Foo bar={baz} />

Props attribute

  • JSX attribute names use camelCase in camel style.

    // bad
    <Foo
      UserName="hello"
      phone_number={12345678}
    />
    
    // good
    <Foo
      userName="hello"
      phoneNumber={12345678}
    />
  • If the attribute value is true, it can be omitted directly.eslint: react/jsx-boolean-value

    // bad
    <Foo
      hidden={true}
    />
    
    // good
    <Foo
      hidden
    />
  • The < img > tag always adds an alt attribute. If the image is displayed in presentation (feel like a PPT display?), ALT can be empty, or < img > should contain role="presentation". eslint: jsx-a11y/img-has-alt

    // bad
    <img src="hello.jpg" />
    
    // good
    <img src="hello.jpg" alt="Me waving hello" />
    
    // good
    <img src="hello.jpg" alt="" />
    
    // good
    <img src="hello.jpg" role="presentation" />
  • Don't use words such as "image", "photo" or "picture" in alt values, including image meanings. The same is true in Chinese. jsx-a11y/img-redundant-alt

Why? The screen reader has labeled the img tag as a picture, so there's no need to explain it in alt.

// bad
<img src="hello.jpg" alt="Picture of me waving hello" />

// good
<img src="hello.jpg" alt="Me waving hello" />
  • Use valid and correct aria role attribute values ARIA roles. eslint: jsx-a11y/aria-role

    // bad - not an ARIA role
    <div role="datepicker" />
    
    // bad - abstract ARIA role
    <div role="range" />
    
    // good
    <div role="button" />
  • Do not use the accessKey attribute on tags. eslint: jsx-a11y/no-access-key

Why? The inconsistency between keyboard shortcuts and keyboard commands caused by screen readers can lead to more complex reading.

// bad
<div accessKey="h" />

// good
<div />
  • Avoid using array index as the value of attribute key, recommend using unique ID..( Why?)

    // bad
    {todos.map((todo, index) =>
      <Todo
        {...todo}
        key={index}
      />
    )}
    
    // good
    {todos.map(todo => (
      <Todo
        {...todo}
        key={todo.id}
      />
    ))}
  • For all non-essential attributes, defaultProps attributes are always defined manually.

Why? ProTypes can be used as documentation for modules, and declaring defaultProps means that people reading code do not need to assume some default values. More importantly, the declared default properties displayed allow your module to skip checking for attribute types.

// bad
function SFC({ foo, bar, children }) {
  return <div>{foo}{bar}{children}</div>;
}
SFC.propTypes = {
  foo: PropTypes.number.isRequired,
  bar: PropTypes.string,
  children: PropTypes.node,
};

// good
function SFC({ foo, bar }) {
  return <div>{foo}{bar}</div>;
}
SFC.propTypes = {
  foo: PropTypes.number.isRequired,
  bar: PropTypes.string,
};
SFC.defaultProps = {
  bar: '',
  children: null,
};

Refs

  • Always use callback functions in Refs.eslint: react/no-string-refs

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

Parentheses parentheses

  • Write multi-line JSX tags in (). eslint: react/wrap-multilines

    // bad
    render() {
    return <MyComponent className="long body" foo="bar">
         <MyChild />
       </MyComponent>;
    }
    
    // good
    render() {
    return (
      <MyComponent className="long body" foo="bar">
    <MyChild />
      </MyComponent>
    );
    }
    
    // good, a single line can be unnecessary
    render() {
    const body = <div>hello</div>;
    return <MyComponent>{body}</MyComponent>;
    }

Tags Tags

  • For tags without child elements, always close the tag by yourself. react/self-closing-comp

    // bad
    <Foo className="stuff"></Foo>
    
    // good
    <Foo className="stuff" />
  • If the module has multiple line attributes, create a new line when closing the label. eslint: react/jsx-closing-bracket-location

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

Methods function

  • Use arrow functions to get local variables.

    function ItemList(props) {
      return (
        <ul>
          {props.items.map((item, index) => (
            <Item
              key={item.key}
              onClick={() => doSomethingWith(item.name, index)}
            />
          ))}
        </ul>
      );
    }
  • When using event handling in render(), bind this in the constructor ahead of time. react/jsx-no-bind

Why? In every render process, calling bind creates a new function, which wastes resources.

// 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} />
  }
}
  • In the React module, don't prefix so-called private functions, it's not private in nature.

Why? _ Underline prefixes are often used to represent private variables or functions in some languages. But unlike some other languages, there is no native support for so-called private variables in JS, and all variable functions are common. Although your intention is to privatize it, underlining before it does not privatize these variables, and all attributes (including those with and without prefixes) should be considered common. For more details, see Issue #1024 , and #490 .

// bad
React.createClass({
  _onClickSubmit() {
    // do stuff
  },

  // other stuff
});

// good
class extends React.Component {
  onClickSubmit() {
    // do stuff
  }

  // other stuff
}
  • In render methods, always ensure the return return value.eslint: react/require-render-return

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

Ordering React module life cycle

  • class extends React.Component's life cycle function:

  1. Optional static Method

  2. Constructor constructor

  3. GettChildContext Gets the child element content

  4. Before rendering the component WillMount module

  5. After rendering the component DidMount module

  6. CompoonentWillReceiveProps module will accept new data

  7. Should Component Update Judgement Module Needs No Rendering

  8. The method above componentWillUpdate returns true, and the module will be rendered again

  9. Completion of rendering for component DidUpdate module

  10. The component WillUnmount module will be cleared from the DOM to do some cleaning tasks

  11. Click the callback or event handler such as onClickSubmit() or onChangeDescription()

  12. getter methods in render, such as getSelectReason() or getFooterContent()

  13. Optional render methods such as renderNavigation() or renderProfilePicture()

  14. render render() Method

  • How to define propTypes, defaultProps, contextTypes, Wait for other attributes...

    import React, { PropTypes } from 'react';
    
    const propTypes = {
      id: PropTypes.number.isRequired,
      url: PropTypes.string.isRequired,
      text: PropTypes.string,
    };
    
    const defaultProps = {
      text: 'Hello World',
    };
    
    class Link extends React.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;
    
    export default Link;
  • The life cycle function of React.createClass is slightly different from that of using class: eslint: react/sort-comp

  1. displayName Setting Module Name

  2. propTypes Sets the Type of Properties

  3. contextTypes Set Context Types

  4. childContextTypes sets the child element context type

  5. Mixers add some mixins

  6. statics

  7. defaultProps Set default property values

  8. getDefaultProps Get the default attribute value

  9. getInitialState Or the initial state

  10. getChildContext

  11. componentWillMount

  12. componentDidMount

  13. componentWillReceiveProps

  14. shouldComponentUpdate

  15. componentWillUpdate

  16. componentDidUpdate

  17. componentWillUnmount

  18. clickHandlers or eventHandlers like onClickSubmit() or onChangeDescription()

  19. getter methods for render like getSelectReason() or getFooterContent()

  20. Optional render methods like renderNavigation() or renderProfilePicture()

  21. render

isMounted

Why? isMounted Anti-Human Design Patterns: () This method is not available in ES6 classes and will be deleted in future versions.

Back to the top

Posted by stelthius on Sun, 14 Apr 2019 10:06:31 -0700