Code Style

June 19, 2017 · View on GitHub

I am a web and mobile developer, using React and React Native. As such, my style has evolved to work more seamlessly with React, and may not work for other frameworks. Also, I LOVE Ruby’s (and CoffeeScript’s) syntax. It taught me the value of code that reads more like english and how aesthetics of a code base truly will affect your and others excitement to maintain/contribute to it.

Code Style

Semicolons

No

// Bad
import Foo from 'foo';
let foo;

// Good
import Foo from 'foo'
let foo

Why

I don’t have any real beef with them, but my code looks better, is more consistent, and faster to write.

  • Looks better is subjective, so I won't go into it. Just look at examples or try it before you decide, please.
  • More consistent because my js looks as my js looks in jsx.
    • For example:
    • <div>{someJavascriptCode()}</div>
    • vs
    • <div>{someJavascriptCode();}</div>
    • Which are you used to seeing in your renders?
  • Faster to code. More than just not hitting the ;, also the time saved from the linter error telling you to add it. You all know you’re guilty of the linter error from time to time.

Quotes

Single

// Bad
const double = "double"

// Good
const single = 'single'

Why?

I used to prefer double because it is the only valid json quote, and it is used in html. Now, with the rise of transpilers, and me using less .json, I prefer the lazy approach of the non-shift-'. It is faster to type, and more importantly, faster to edit. For example, in vim, ci' is honestly way less taxing than ci<shift>'.

Spacing

The following spacing rules are used to satisfy the "reads more like english" request. In general, pad spaces are used around parameters and arguments, and not used around types.

Paren spacing in function args and params?

Yes

// Bad
function myFunc(one, two, three) { ... }

myFunc(a, b, c)

// Good
function myFunc( one, two, three ) { ... }

myFunc( a, b, c )

Except: desctructured params

// Good
function myFunc({ one, two, three }) { ... }

Except: arrow params

// Good
const arrow = (one, two, three) => { ... }

// Good
array.sort( (item, index) => ... )

Why

With arrow params, the added spacing is redundant since it is already padded with spacing outside of the parens.

Paren spacing in statement expressions (like if, switch, logic)?

No

// Bad
if ( x > y ) { ... }

// Good
if (x > y) { ... }

Why

Here, the added spacing in the if expression is redundant since it is already padded with spacing outside of the parens.

Curly spacing in objects

No

// Bad
const obj = { a: 'a', b: 'b' }

// Good
const obj = {a: 'a', b: 'b'}

Why

The lack of spacing clearly denotes that this is a type, and is not destructured.

Curly spacing in destructuring assignments?

Yes

// Bad
import {MyComponent} from 'components'
const {user} = this.props

// Good
import { MyComponent } from 'components'
const { user } = this.props

Why

The spacing here is redundant, but also really useful for skimming code and distinguishing destructuring from objects.

Bracket spacing in array inits

No

// Bad
const obj = [ 1, 2, 3 ]

// Good
const obj = [1, 2, 3]

Why

The lack of spacing clearly denotes that this is a type, and is not destructured.

Bracket spacing in object reference and destructuring

Yes

// Bad
const [a, b] = someArray
const a = someArray[0]

// Good
const [ a, b ] = someArray
const a = someArray[ 0 ]

Why

Destructuring for reasons above. Space in reference for "reading like english", same as function args/params.

if/else

spacing

// Bad
if (isCondition1) {
} else if (isCondition2) {
} else {
}

// Good
if (isCondition1) {
}
else if (isCondition2) {
}
else {
}

Why

All revolves around vertical spacing. The more popular style of housing else on the closing } just clutters up the content of condition1 too much. Also, using the more spaced out version that I prefer has revealed refactoring opportunities for more complex nested if statements. Win win. See this twitter thread for other reasons.

Code Conventions

if/else commenting

// Whole if/else comment (likely not needed though)
if (isCondition1) {
  // if condition 1, do...
}
else if (isCondition2) {
  // if condition 2, use...
}
else {
  // otherwise, pass off...
}

Comment on first line of if block IF a comment is necessary. Also using the if _condition_, <verb> format is useful for the reader skimming just the comments.

Function approach

You want to get right to the meat of your function’s purpose. Do not defensively code! This should be done in the function’s parameters.

// Bad
function doSomeCoolLogic( name, names ) {
  if (typeOf name === 'string' && Array.isArray( names )) {
   return names.includes( name )
  }
}

// Good
function doSomeCoolLogic( name = 'default', names = [] ) {
  return names.includes( name )
}

Handler function naming

Passing handlers down as props is common in React.

  • Use __handles__EventName if it is the originating handler for an event
  • Use __on__EventName if it is a function that is calling an onEventName that was passed down to it

Sort function naming

sort functions called by__.

function byNameAscending( a, b ) { ... }

array.sort( byNameAscending() )

React-specific conventions

In general, keep your components as small and focussed as possible (and reasonable). The conventions below will help with this.

Use get functions for derived and computed props/state

get fullName() {
  return `${this.props.firstName} ${this.props.lastName}`
}

render() {
  return (
    <Text>{this.fullName}</Text>
  )
}

Reference

react-bits/03.computed-props-state.jsx

Imports order

Structure your imports like: functions, constants, vertical space, then components. Each block should be ordered as external, then local.

// Good
import React from 'react'                                 // external
import { connect } from 'react-redux'                     // external
import { ANIMATION_TIMING } from 'constants'              // local

import {
  View,
  Text,
  TouchableOpacity,
} from 'react-native'                                     // external
import NavBar form 'react-native-navbar'                  // external
import MyAnimatedComponent from './MyAnimatedComponent'   // local

class MyComponent extends React.Component { ... }

Why

This allows you to more easily skim and parse a component's dependencies.

Stateless functional components

Gone are the days of renderSection(). Now you should be using a stateless functional component. Note, any exported component should probably still be the class style so that you have access to shouldComponentUpdate and such. Otherwise, consider Recompose.

// Bad
class MyComponent extends React.Component {
 renderItem() {
  return <div/>
 }

 render() {
  return (
   <div>
    {this.renderItem()}
   </div>
  )
 }
}

// Good
const Item = props => <div/>

class MyComponent extends React.Component {
 render() {
  return (
   <div>
    <Item />
   </div>
  )
 }
}

Why

Why not use render___() in components? They spiral out of control. You should be building subcomponents instead!

Extract non-this functions out of component

Utility functions that do not actually use any instance properties should not exist within the component definition. They should be above the component definition, or in some separate, imported helpers file.

// Bad
class MyComponent extends React.Component {
 getNamesFromItems( items = [] ) {
  return items.find( item => item.name )
 }

 render() {
  const names = this.getNamesFromItems( this.props.items )

  return ( ... )
 }
}

// Good
function getNamesFromItems( items = [] ) {
  return items.find( item => item.name )
}

class MyComponent extends React.Component {
 render() {
  const names = getNamesFromItems( this.props.items )

  return ( ... )
 }
}

inline styles

Inline styles place at the bottom of the file for RN (and web React if using something like Radium).

_privateMethod vs publicMethod

Since ~99% of components will use props, and not be accessed via public methods, prefer the publicMethod format for all functions, and clearly comment when one is truly public (in that a component will use this.refs.myComponent.publicMethod()).

// Bad
class MyComponent extends React.Component {
 ...

 _resetScrollValue() {
  this.setState({ scrollValue: 0 })
 }

 scrollTo( scrollValue = 0 ) {
  this.setState({ scrollValue })
 }
 ...
}

// Good
class MyComponent extends React.Component {
 ...

 resetScrollValue() {
  this.setState({ scrollValue: 0 })
 }

 /* PUBLIC */
 scrollTo( scrollValue = 0 ) {
  this.setState({ scrollValue })
 }
 ...
}

Some good resources

9 things every React.js beginner should know - Cam Jackson