Here you can read about how we build our React applications.
React is a widely-used library from Facebook for building user interfaces.
Use stateless functional components when possible. Class components are only necessary when you need a local state, e.g. input fields.
Logic should not be performed in the render
method or in functional components, because it may have severe performance implications. The reason for this is that components may be rendered tens of times every second, which in turn means that the logic will be evaluated as many times.
Do
const Hello = ({message}) =>
<h1>Hello World</h1>
Do NOT do
class Hello extends Component {
render() {
return <h1>Hello World</h1>
}
}
Use higher-order components (or decorators) to reuse component logic. A higher-order component is a function that takes a component and returns a new component.
Use context together with [higher-order components](#Higher-Order Components) to pass props down the component tree when necessary. Context should be avoided when possible, because it makes the application more complex and harder to understand.
Use MobX to manage the application state in separate stores.
You should also let MobX manage component state.
Do
import React, {Component} from 'react'
import {observable} from 'mobx'
import {observer} from 'mobx-react'
class Hello extends Component {
@observable message: string = ''
render() {
return (
<div>
<p>{this.message}</p>
<button onClick={() => this.message = 'Hello.'}>Say Hello</button>
</div>
)
}
}
Do NOT do
import React, {Component} from 'react'
type State = {
message: string,
}
class Hello extends Component {
state: State = {message: ''}
render() {
return (
<div>
<p>{this.state.message}</p>
<button onClick={() => this.setState({message: 'Hello.'}}>Say Hello</button>
</div>
)
}
}
You can use this very project as a real-world example of how to combine all of this for your projects.
Use React Router to create routes for your application.
Use lodash (or a similar utility library) instead of writing your own utility functions. Even though you might think that you do not need an utility library at first, you will need it sooner or later.
Here are some useful utility functions:
Try keep your direction structure as flat as possible and group your code by feature, and not by type. Nothing is more frustrating than navigating the file tree every time you need to find the selector for the component you are working on or the reducer that you are writing a test for. It is much easier to place all files that are associated with each other under the same directory.
React components are an exception to this, because it is better to keep them separate for clarity.
Note: Your source code should always be placed in a src
directory.
Do
src/
todo/
components/
Todos.js
Todo.css
actions.js
reducer.js
selectors.js
spec.js
index.js
test.js
Do NOT do
src/
actions/
todo.js
components/
Todos.js
reducers/
todo.js
selectors/
todo.js
styles
Todo.css
spec/
todo.js
You should write unit tests at least for the most important parts of your application, because it will make it easier to both develop and refactor the application. Having some unit tests will also make it easier for new developers to join project, as they can verify that everything still works as intended after making a change.
Focus on writing unit tests that ensure that your application is behaves correctly instead of testing every part of the application separately. Testing everything separately is time-consuming and it makes refactoring the application a nightmare, because you will spend a lot of time updating the test cases.
We have found Jest and Enzyme to be the best libraries for testing React applications.
Protip: You can use Jest Snapshot Testing to test your React components without writing complex test cases.
Use Husky to ensure that the code works before it is committed.
You should run at least the following tasks before each commit:
- Linting
- Unit tests
- Type-checking (if applicable)
Protip: Husky supports all Git hooks. Simply add the corresponding npm script
to your package.json
.