Skip to content

Instantly share code, notes, and snippets.

@avegancafe
Last active October 4, 2018 17:34
Show Gist options
  • Select an option

  • Save avegancafe/131962d6038820bc2b26a14ec8c4b433 to your computer and use it in GitHub Desktop.

Select an option

Save avegancafe/131962d6038820bc2b26a14ec8c4b433 to your computer and use it in GitHub Desktop.

React Code Style Guide

This is our style guide for how we write our react code at VTS. Some of them are preferences, but if we all try to stick to them as much as possible hopefully we can have a maintainable, easy to read codebase. If something is not listed here, then we generally abide by the AirBnB's react style guide. If it's not in there either, use your best judgement.

Table of Contents

  1. Syntax
  2. High-level Patterns
  3. Library Changes or Deprecations
  4. FAQ
  5. Outstanding Questions

Syntax

These are some rules to help us try to keep a clean, readable, bug-free codebase. The more we standardize on some of these simple style rules, the easier it will be to jump into someone else's code and understand what's going on.

  • 1.1 Prefer specific module imports over global imports for libraries
// correct
import map from 'lodash/map'

// incorrect
import { map } from 'lodash'

  • 1.2 Prop naming and declaration
    • Put the propTypes declaration at the bottom of the file
    • Action props start with on
    • Method to be passed to an onSomeActionHappened prop should start with handle
// SomeComponent.js

export const SomeComponent = () => <div></div>;

SomeComponent.propTypes = {
  // Default handler if you have a single value
  onChange: PropTypes.func,

  // Default name for model if you only have one data binding
  value: PropTypes.any,
};


// UseSomeComponent.js

export class UseSomeComponent extends Component {
  handleSomeChange = () => { /* Do whatever you need to do onChange of SomeComponent */ };

  render() {
    return <SomeComponent onChange={this.handleSomeChange} />;
  }
};

  • 1.3 Prefer class field declarations instead of binding in the constructor
// incorrect
export class SomeComponent extends Component {
  constructor() {
    this.state = {
      inputModel: ""
    };
    this.handleInputChange = () => { /* Do what you have gotta do */ };

    SomeService.find().then(() => { /* Do a thing */ });
  }
};

// correct
export class SomeComponent extends Component {
  state = {
    inputModel: ""
  };

  handleInputChange = () => { /* Do what you gotta do */ };

  constructor() {
    SomeService.find().then(() => { /* Do a thing */ });
  }
};

  • 1.4 Inside of JSX, only use ternary operators and avoid boolean operators
    • This helps us be more speciefic with our return values, as well as conveying intent of the resolved value to the reader.
// incorrect
export const SomeComponent = ({ showIcon = true }) => (
  <div>
    // this could return any falsey value, e.g. 0
    { showIcon && (<i class="icon-mag" />) }
    <span>Hello, world!</span>
  </div>
);

// correct
export const SomeComponent = ({ showIcon = true }) => (
  <div>
    // this is much more specific, will always return only either <i /> or null
    { showIcon ? <i class="icon-mag" /> : null }
    <span>Hello, world!</span>
  </div>
);

  • 1.5 Use Pascal case if you're importing a full library import, camel case if it's just a function or util
    • Whether it's the default import or a named import, doing this lets us more easily read usage of our 3rd party libraries
// incorrect
import propTypes from "prop-types";
import ClassNames from "classNames";
import Map from "lodash/map";
import Flatten from "lodash/flatten";

// correct
import PropTypes from "prop-types";
import classNames from "classNames";
import map from "lodash/map";
import flatten from "lodash/flatten";

High-level Patterns

This is for larger questions, e.g. where should I put files, how should I test components, etc.

  • 2.1 Our current testing framework consists of:
    • Enzyme
    • Jest
    • Snapshot testing for stable components
  • 2.2 Our overall folder structure is approximately as follows:
    • A couple different root directories at the top level in react-ui:
      • views: All components that are page specific. Grouped by business case.
      • shared: All shared components.
    • File naming:
      • Services: vts-core/services/comps/comps-service.js
      • React components: react-ui/shared/Modal.js
      • Angular components: angular-ui/proposal-form/new-proposal-form.js
    • Folder naming:
      • Always kebab case

Library changes or deprecations

Don't use Angular! Kidding (but not really). This section is for any changes in libraries that we're trying to implement, whether it be a different usage of an existing dependency or deprecation of a lib in our app.

  • 3.1 Prefer to not use jQuery when at all possible
  • 3.2 Prefer native APIs over lodash. If there's a reason to use lodash then it's fine.
  • 3.3 Always use ng to import to access angular service dependencies if their data is not in the redux store already

FAQ

  • 4.1 Do we use CSS-in-JS
    • No (for now 😄)
  • 4.2 Do we put hard-coded constants on the store or in the component
    • Okay with current pattern for now, figure out if we want to change it later when working on TIMs

Outstanding Questions

  • 5.1 Do we use redux for state management & making requests
  • 5.2 Do we use react contexts
  • 5.3 What tool do we use for our style guide?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment