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.
// Bad
import Foo from 'foo';
let foo;
// Good
import Foo from 'foo'
let foo
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.
// Bad
const double = "double"
// Good
const single = 'single'
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>'
.
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.
// Bad
function myFunc(one, two, three) { ... }
myFunc(a, b, c)
// Good
function myFunc( one, two, three ) { ... }
myFunc( a, b, c )
// Good
function myFunc({ one, two, three }) { ... }
// Good
const arrow = (one, two, three) => { ... }
// Good
array.sort( (item, index) => ... )
With arrow params, the added spacing is redundant since it is already padded with spacing outside of the parens.
// Bad
if ( x > y ) { ... }
// Good
if (x > y) { ... }
Here, the added spacing in the if
expression is redundant since it is already padded with spacing outside of the parens.
// Bad
const obj = { a: 'a', b: 'b' }
// Good
const obj = {a: 'a', b: 'b'}
The lack of spacing clearly denotes that this is a type, and is not destructured.
// Bad
import {MyComponent} from 'components'
const {user} = this.props
// Good
import { MyComponent } from 'components'
const { user } = this.props
The spacing here is redundant, but also really useful for skimming code and distinguishing destructuring from objects.
// Bad
const obj = [ 1, 2, 3 ]
// Good
const obj = [1, 2, 3]
The lack of spacing clearly denotes that this is a type, and is not destructured.
// Bad
const [a, b] = someArray
const a = someArray[0]
// Good
const [ a, b ] = someArray
const a = someArray[ 0 ]
Destructuring for reasons above. Space in reference for "reading like english", same as function args/params.
// Bad
if (isCondition1) {
} else if (isCondition2) {
} else {
}
// Good
if (isCondition1) {
}
else if (isCondition2) {
}
else {
}
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.
// 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.
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 )
}
Passing handlers down as props is common in React.
- Use handlesEventName if it is the originating handler for an event
- Use onEventName if it is a function that is calling an onEventName that was passed down to it
sort functions called by__.
function byNameAscending( a, b ) { ... }
array.sort( byNameAscending() )
In general, keep your components as small and focussed as possible (and reasonable). The conventions below will help with this.
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>
)
}
}
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 place at the bottom of the file for RN (and web React if using something like Radium).
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 })
}
...
}