React ⚡️

Hero image for React ⚡️

Formatting

  • Use soft-tabs with a two space indent.
  • Limit each line of code to fewer than 130 characters.
  • End each file with a newline.

Naming

  • Use jsx extensions for components, screens etc.
  • Use PascalCase for files with the jsx extension:

    components/
    ├── Button/
    │   ├── index.jsx
    screens/
    ├── Home/
    │   ├── index.jsx
    

    index.jsx is the only exception to this rule as it represents the folder root. This filename can also be omitted in import statements: import Button from '../Button/'.

  • Use camelCase for all other files with a js extension:

    lib/
    ├── requestManager.js
    helpers/
    ├── userHelper.js
    
  • Use camelCase for variables and functions:

    // Bad
    let form_params = {};
      
    function FetchParams() { 
      return {};
    }
    
    // Good
    let formParams = {};
      
    function fetchParams() { 
      return {};
    }
    
  • Use PascalCase for classes:

    // Bad
    class product_form {}
    class productForm {}
      
    // Good
    class ProductForm {}
    
  • Use SCREAMING_SNAKE_CASE for constants:

    // Bad
    const fetchLimit = 25;
      
    // Good
    const FETCH_LIMIT = 25;
    

    This formatting is somewhat inherited from Ruby but is widely accepted in the JS community.

  • Use camelCase for prop names and PascalCase if the prop value is a React component:

    
    // Bad
    <Foo
      UserName='hello'
      phone_number={ 12345678 }
    />
      
    // Good
    <Foo
      userName='hello'
      phoneNumber={ 12345678 }
      Component={ SomeComponent }
    />
    

Props

  • Omit the value of the prop when it is explicitly true:

    // Bad
    <Foo
      hidden={true}
    />
      
    // Good
    <Foo hidden />
    
  • Always include an alt prop on tags. If the image is presentational, alt can be an empty string or the must have role=’presentation’:

    // 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' />
    
  • Avoid using an array index as key prop, prefer a stable ID:

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

Tags

  • For single components (having no children), always use self-close tags.

    // Bad
    <Foo variant="noChildren"></Foo>
    
    // Good
    <Foo variant="noChildren" />
    
  • For component with multi-line properties, close the tag on a new line

    // Bad
    <Foo
      bar="bar"
      foo="foo" />
      
    // Good
    <Foo
      bar="bar"
      foo="foo"
    />
    

Functions

  • Use arrow functions to close over local variables.

    function TaskList(props) {
      return (
        <ul>
          {props.tasks.map((task, index) => (
            <Item
              key={task.key}
              onClick={() => someFunc(task.name, index)}
            />
          ))}
        </ul>
      );
    }
    
  • In the constructor, Bind event handlers for the render method, Otherwise it creates a whole new function on every single render and reduces performance.

    // Bad
    class extends React.Component {
      onClickDiv() {
        ....
      }
      
      render() {
        return <div onClick={this.onClickDiv.bind(this)} />;
      }
    }
      
    // Good
    class extends React.Component {
      constructor(props) {
        super(props);
      
        this.onClickDiv = this.onClickDiv.bind(this);
      }
      
      onClickDiv() {
        ....
      }
      
      render() {
        return <div onClick={this.onClickDiv} />;
      }
    }
    
  • Be sure to return a value in render methods.

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

Project Structure

After working on several React projects, we settled down on the following file organization (this structure is closed to the general JS application structure):

adapters/
├── product.js
components/
├── Product/
│   ├── index.jsx
├── ProductList/
│   ├── index.jsx
constants/
├── product.js
contexts/
├── auth.js
helpers/
├── formatProductDescription.js
reducers/
├── product.js
screens/
├── ProductDetails/
│   ├── index.jsx
services/
├── googleMap.js
tests/
├── components/
│   ├── Product/
│   │   ├── index.test.js
  • adapters/: the classes in charge of making network and/or async tasks. We usually create one file per API resource.

  • components/: the stateless and reusable React components.

  • constants/: the reducers types under this directory. The organization of this directory should match the folder structure of the reducers.

  • contexts: creating contexts and context providers.

  • helpers/: Any utilities used in the project.

  • reducers/: the Redux reducers. The organization of this directory should match the folder structure of contexts and constants.

  • screens/: the page specific components which are in charge of rendering all other stateless components to build any specific page.

  • services/: the service classes used in the project. By definition, these classes should encapsulate one single process of the app.

  • tests: Unit tests for components, screens, helpers etc.

Components / Screens

Use a folder structure with an index file (and other files when required):

// Bad
components/
├── Button.jsx
screens/
├── Product.jsx

// Good
components/
├── Button/
│   ├── index.jsx
screens/
├── ProductDetails/
│   ├── index.jsx

This is both a future-proof measure and a mean to break down components into small meaningful modules:

components/
├── Button/
│   ├── index.jsx
│   ├── loading.jsx
│   ├── propTypes.js
screens/
├── ProductDetails/
│   ├── index.jsx
│   ├── header.jsx
│   ├── gallery.jsx

Component Props

React PropTypes are a critical part of creating re-usable components with a clear API.

  • Use the right PropType that matches the expected data type for each prop:

    Button.propTypes = {
      /**
       * Holds the text to display in the button.
       **/
      text: PropTypes.string,
      
      /**
       * Disabled state
       **/
      disabled: PropTypes.bool,
      
      /**
       * Click event handler.
       **/
      onClick: PropTypes.func,
        
      /**
      * Select the style type.
      **/
      styleType: PropTypes.oneOf(['default', 'primary', 'secondary'])
    };
      
    
  • Define which prop is required:

    Button.propTypes = {
      /**
       * Holds the text to display in the button.
       **/
      text: PropTypes.string.isRequired,
      
      /**
       * Disabled state
       **/
      disabled: PropTypes.bool
    };
      
    
  • Use PropTypes.shape to define complex props:

    /**
    * Available action creators.
    **/
    actions: PropTypes.shape({
        /**
         * When a ticket is selected.
         **/
        pickTicket: PropTypes.func.isRequired,
          
        /**
         * When a ticket is unselected.
         **/
        unpickTicket: PropTypes.func.isRequired
    }).isRequired
      
    /**
     * Holds the search store.
     * */
    search: PropTypes.shape({
        /**
         * Holds the origin city.
         **/
        origin: PropTypes.string.isRequired,
          
        /**
         * Holds the destination city.
         **/
        destination: PPropTypes.string.isRequired
    }).isRequired
    

The definition of PropTypes allows for complex type structure between components:

components/
├── Product/
│   ├── index.jsx
│   ├── propTypes.js
├── Feed/
│   ├── index.jsx
│   ├── propTypes.js

In Feed/propTypes.js:

import PropTypes from 'prop-types';
import productPropType from '../Product/propTypes';

export const feedPropType = PropTypes.shape({
  products: PropTypes.arrayOf(productPropType).isRequired,
  ...
});

Tests

The tests folder should have unit tests for the application. The folder structure of the tests should be similar to the structure of the application. For example if we have a product.js file in below structure

components/
├── Product/
│   ├── product.js

then the structure in tests folder should be

tests/
├── components/
│   ├── Product/
│   │   ├── product.test.js    

Many of the React formatting conventions derived from the Javascript conventions.