React.js Best Practices

RisingStack's services:

Sign up to our newsletter!

In this article:

2015 was the year of React with tons of new releases and developer conferences dedicated to the topic all over the world. For a detailed list of the most important milestones of last year, check out our React in 2015 wrap up.

The most interesting question for 2016: How should we write an application and what are the recommended libraries?

As a developer working for a long time with React.js I have my own answers and best practices, but it’s possible that you won’t agree on everything with me. I’m interested in your ideas and opinions: please leave a comment so we can discuss them.

If you are just getting started with React.js, check out our React.js tutorial, or the React howto by Pete Hunt. Also, if you’d like learn the basics of Nodejs, get started here.

Dealing with data

Handling data in a React.js application is super easy, but challenging at the same time.
It happens because you can pass properties to a React component in a lot of ways to build a rendering tree from it; however it’s not always obvious how you should update your view.

2015 started with the releases of different Flux libraries and continued with more functional and reactive solutions.

Let’s see where we are now:

Flux

According to our experience, Flux is often overused (meaning that people use it even if they don’t even need it).

Flux provides a clean way to store and update your application’s state and trigger rendering when it’s needed.

Flux can be useful for the app’s global states like: managing logged in user, the state of a router or active account but it can turn quickly into pain if you start to manage your temporary or local data with it.

We don’t recommend using Flux for managing route-related data like /items/:itemId. Instead, just fetch it and store it in your component’s state. In this case, it will be destroyed when your component goes away.

If you need more info about Flux, The Evolution of Flux Frameworks is a great read.

Use redux

Redux is a predictable state container for JavaScript apps.

If you think you need Flux or a similar solution you should check out redux and Dan Abramov‘s Getting started with redux course to quickly boost your development skills.

Redux evolves the ideas of Flux but avoids its complexity by taking cues from Elm.

Keep your state flat

API’s often return nested resources. It can be hard to deal with them in a Flux or Redux-based architecture. We recommend to flatten them with a library like normalizr and keep your state as flat as possible.

Hint for pros:

const data = normalize(response, arrayOf(schema.user))

state = _.merge(state, data.entities)

(we use isomorphic-fetch to communicate with our APIs)

Use immutable states

Shared mutable state is the root of all evil – Pete Hunt, React.js Conf 2015

Immutable logo for React.js Best Practices 2016

Immutable object is an object whose state cannot be modified after it is created.

Immutable objects can save us all a headache and improve the rendering performance with their reference-level equality checks. Like in the shouldComponentUpdate:

shouldComponentUpdate(nexProps) {
 // instead of object deep comparsion
 return this.props.immutableFoo !== nexProps.immutableFoo
}

How to achieve immutability in JavaScript?

The hard way is to be careful and write code like the example below, which you should always check in your unit tests with deep-freeze-node (freeze before the mutation and verify the result after it).

return {
  ...state,
  foo
}

return arr1.concat(arr2)

Believe me, these were the pretty obvious examples.

The less complicated way but also less natural one is to use Immutable.js.

import { fromJS } from 'immutable'

const state = fromJS({ bar: 'biz' })
const newState = foo.set('bar', 'baz')

Immutable.js is fast, and the idea behind it is beautiful. I recommend watching the Immutable Data and React video by Lee Byron even if you don’t want to use it. It will give deep insight to understand how it works.

Observables and reactive solutions

If you don’t like Flux/Redux or just want to be more reactive, don’t be disappointed! There are other solutions to deal with your data. Here is a short list of libraries what you are probably looking for:

  • cycle.js (“A functional and reactive JavaScript framework for cleaner code”)
  • rx-flux (“The Flux architecture with RxJS”)
  • redux-rx (“RxJS utilities for Redux.”)
  • mobservable (“Observable data. Reactive functions. Simple code.”)

Routing

Almost every client side application has some routing. If you are using React.js in a browser, you will reach the point when you should pick a library.

Our chosen one is the react-router by the excellent rackt community. Rackt always ships quality resources for React.js lovers.

To integrate react-router check out their documentation, but what’s more important here: if you use Flux/Redux we recommend to keep your router’s state in sync with your store/global state.

Synchronized router states will help you to control router behaviors by Flux/Redux actions and read router states and parameters in your components.

Redux users can simply do it with the redux-simple-router library.

Code splitting, lazy loading

Only a few of webpack users know that it’s possible to split your application’s code to separate the bundler’s output to multiple JavaScript chunks:

require.ensure([], () => {
  const Profile = require('./Profile.js')
  this.setState({
    currentComponent: Profile
  })
})

It can be extremely useful in large applications because the user’s browser doesn’t have to download rarely used codes like the profile page after every deploy.

Having more chunks will cause more HTTP requests – but that’s not a problem with HTTP/2 multiplexed.

Combining with chunk hashing you can also optimize your cache hit ratio after code changes.

The next version of react-router will help a lot in code splitting.

For the future of react-router check out this blog post by Ryan FlorenceWelcome to Future of Web Application Delivery.

Components

A lot of people are complaining about JSX. First of all, you should know that it’s optional in React.

At the end of the day, it will be compiled to JavaScript with Babel. You can write JavaScript instead of JSX, but it feels more natural to use JSX while you are working with HTML.
Especially because even less technical people could still understand and modify the required parts.

JSX is a JavaScript syntax extension that looks similar to XML. You can use a simple JSX syntactic transform with React. – JSX in depth

If you want to read more about JSX check out the JSX Looks Like An Abomination – But it’s Good for You article.

Use Classes

React works well with ES2015 classes.

class HelloMessage extends React.Component {
  render() {
    return <div>Hello {this.props.name}</div>
  }
}

We prefer higher order components over mixins so for us leaving createClass was more like a syntactical question rather than a technical one. We believe there is nothing wrong with using createClass over React.Component and vice-versa.

PropType

If you still don’t check your properties, you should start 2016 with fixing this. It can save hours for you, believe me.

MyComponent.propTypes = {
  isLoading: PropTypes.bool.isRequired,
  items: ImmutablePropTypes.listOf(
    ImmutablePropTypes.contains({
      name: PropTypes.string.isRequired,
    })
  ).isRequired
}

Yes, it’s possible to validate Immutable.js properties as well with react-immutable-proptypes.

Higher order components

Now that mixins are dead and not supported in ES6 Class components we should look for a different approach.

What is a higher order component?

PassData({ foo: 'bar' })(MyComponent)

Basically, you compose a new component from your original one and extend its behaviour. You can use it in various situations like authentication: requireAuth({ role: 'admin' })(MyComponent) (check for a user in higher component and redirect if the user is not logged in) or connecting your component with Flux/Redux store.

At RisingStack, we also like to separate data fetching and controller-like logic to higher order components and keep our views as simple as possible.

Testing

Testing with good test coverage must be an important part of your development cycle. Luckily, the React.js community came up with excellent libraries to help us achieve this.

Component testing

One of our favorite library for component testing is enzyme by AirBnb. With it’s shallow rendering feature you can test logic and rendering output of your components, which is pretty amazing. It still cannot replace your selenium tests, but you can step up to a new level of frontend testing with it.

it('simulates click events', () => {
  const onButtonClick = sinon.spy()
  const wrapper = shallow(
    <Foo onButtonClick={onButtonClick} />
  )
  wrapper.find('button').simulate('click')
  expect(onButtonClick.calledOnce).to.be.true
})

Looks neat, isn’t it?

Do you use chai as assertion library? You will like chai-enyzime!

Redux testing

Testing a reducer should be easy, it responds to the incoming actions and turns the previous state to a new one:

it('should set token', () => {
  const nextState = reducer(undefined, {
    type: USER_SET_TOKEN,
    token: 'my-token'
  })

  // immutable.js state output
  expect(nextState.toJS()).to.be.eql({
    token: 'my-token'
  })
})

Testing actions is simple until you start to use async ones. For testing async redux actions we recommend to check out redux-mock-store, it can help a lot.

it('should dispatch action', (done) => {
  const getState = {}
  const action = { type: 'ADD_TODO' }
  const expectedActions = [action]
 
  const store = mockStore(getState, expectedActions, done)
  store.dispatch(action)
})

For deeper redux testing visit the official documentation.

Use npm

However React.js works well without code bundling we recommend using Webpack or Browserify to have the power of npm. Npm is full of quality React.js packages, and it can help to manage your dependencies in a nice way.

(Please don’t forget to reuse your own components, it’s an excellent way to optimize your code.)

Bundle size

This question is not React-related but because most people bundle their React application I think it’s important to mention it here.

While you are bundling your source code, always be aware of your bundle’s file size. To keep it at the minimum you should consider how you require/import your dependencies.

Check the following code snippet, the two different way can make a huge difference in the output:

import { concat, sortBy, map, sample } from 'lodash'

// vs.
import concat from 'lodash/concat';  
import sortBy from 'lodash/sortBy';  
import map from 'lodash/map';  
import sample from 'lodash/sample';

Check out the Reduce Your bundle.js File Size By Doing This One Thing for more details.

We also like to split our code to least vendors.js and app.js because vendors updates less frequently than our code base.

With hashing the output file names (chunk hash in WebPack) and caching them for the long term, we can dramatically reduce the size of the code what needs to be downloaded by returning visitors on the site. Combining it with lazy loading you can imagine how optimal can it be.

If you are new to Webpack, check out this excellent React webpack cookbook.

Component-level hot reload

If you ever wrote a single page application with livereload, probably you know how annoying it is when you are working on something stateful, and the whole page just reloads while you hit a save in your editor. You have to click through the application again, and you will go crazy repeating this a lot.

With React, it’s possible to reload a component while keeping its states – boom, no more pain!

To setup hot reload check out the react-transform-boilerplate.

Use ES2015

I mentioned that we use JSX in our React.js components what we transpile with Babel.js.

Babel logo in React.js Best Practices 2016

Babel can do much more and also makes possible to write ES6/ES2015 code for browsers today. At RisingStack, we use ES2015 features on both server and client side which are available in the latest LTS Node.js version.

Linters

Maybe you already use a style guide for your JavaScript code but did you know that there are style guides for React as well? We highly recommend to pick one and start following it.

At RisingStack, we also enforce our linters to run on the CI system and for git push as well. Check out pre-push or pre-commit.

We use JavaScript Standard Style for JavaScript with eslint-plugin-react to lint our React.js code.

(That’s right, we do not use semicolons anymore.)

GraphQL and Relay

GraphQL and Relay are relatively new technologies. At RisingStack, we don’t use it in production for now, just keeping our eyes open.

We wrote a library called graffiti which is a MongoDB ORM for Relay and makes it possible to create a GraphQL server from your existing mongoose models.
If you would like to learn these new technologies we recommend to check it out and play with it.

Takeaway from these React.js Best Practices

Some of the highlighted techniques and libraries are not React.js related at all – always keep your eyes open and check what others in the community do. The React community is inspired a lot by the Elm architecture in 2015.

If you know about other essential React.js tools that people should use in 2016, let us know in the comments!

Share this post

Twitter
Facebook
LinkedIn
Reddit