-
Notifications
You must be signed in to change notification settings - Fork 12
JavaScript: React
When we start a new React app, the first question we need to answer is whether or not it will include our Kickoff front-end framework.
If the answer is no, we will use Create React App
If the answer is yes, we will use Create Kickoff App
Both of these projects automate the proper set up of new apps, including using Webpack for module bundling and hot-reloading for development servers.
The latter also includes the Kickoff framework, allowing you to customise a copy of the Kickoff source to suit your project.
Libraries like React Router, Redux, or RxJS may be added as and when appropriate. They should not however, be included "out of the box" as each project will differ.
As with adding any packages, it is important to avoid complexity for complexity's sake.
Ask yourself what the capabilities you want the application to have are, and whether or not that should rely on a library for managing complex state (Redux). It may be enough to have Higher-Order-Components which hold State for their children.
Wherever possible, we should be writing functional components. Compare the following examples:-
import React from 'react'
const Greeting = ({ name }) => <div>Hello {name}!</div>
export default Greeting
import React, { Component } from 'react'
class Greeting extends Component {
constructor (props) {
super(props)
}
render () {
return (
<div>Hello {this.props.name}!</div>
)
}
}
export default Greeting
This is because not only is it more efficient for us to write as few lines as possible, but internally React is able to treat functional components as not having any backing State which can speed up DOM reconciliation when calculating updates.
Naturally there will be sensible cases where a component needs a local state (e.g. a Dropdown which can be expanded or unexpanded, with options that are fetched dynamically from a server).
In these cases extending Component may be warranted, but in an ideal world we would either inherit from PureComponent or implement a reliable shouldComponentUpdate() lifecycle method on the class instance.
- use ES6
importsyntax - only
importthe things you need rather thanrequiringthe entire module and then only using part
// Good
import React, { Component } from 'react'
// Bad
var React = require('react')
var Component = React.Component
- separate your
constdeclarations and yourexports - often we need to wrap
exportsin styling or data handling libraries (e.g. Radium, GraphQL, etc.)
// Good
const Greeting = () => {
...
}
export default Greeting
// Bad
export default Greeting = () => {
...
}
- use Object destructuring to only expose required props to component functions
- don't keep referencing
this.propsorthis.state - don't declare new variables from
this.propsorthis.state
// Good
const Greeting = ({ name }) => <div>Hello {name}!</div>
// Bad
const Greeting = () => <div>Hello {this.props.name}!</div>
// Also Bad
const Greeting = () => {
var name = this.props.name
return <div>Hello {name}!</div>
}
- use ES6 Arrow function syntax
// Good
const Greeting = () => <div>...</div>
// Bad
function Greeting () {
return <div>...</div>
}
If a component needs to load some data before rendering, this data should be fetching in a componentWillMount() method. It should not be fetching in either the constructor() or render() methods.
This could be either a direct AJAX call or an Action dispatch if using a state management library such as Redux.
The reason for this is so that data fetching does not block rendering. You should include a loading... message or component while you are waiting for the response of your AJAX call.
Where it makes sense, abstract utility functions out to a separate module that can be imported by components which depend on that function.
As a general rule, keep components as thin, light, and testable as possible. Avoid using Mixins - these are now considered harmful.