ReactJS best practices for 2016 (second part)

We started last week translating an article on best practices in React.js in 2016. Here is the rest…

Components

A lot of people complain about JSX. First of all, you should know that it is optional in React.
Ultimately, JSX is still compiled to JavaScript with Babel. So you can write JavaScript instead of JSX, although it seems more natural to use JSX as long as you're working in HTML.
Thus, less technical profiles will be able to continue to understand and manipulate this part of the Front front.

JSX is a JavaScript syntax extension that looks like XML. You can use a simple syntactic transformer with React – JSX in-depth

If you want to read more about JSX, take a look at the article JSX Looks Like An Abomination – But it's Good for You.

Use classes

React works well with ES2015 classes.

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

We prefer high-level components over mixins, so for us to drop the createClass  was more a question of syntax than a technical problem. We believe there is nothing wrong with using createClass rather than React.Component  and vice versa.

PropType

If you're still not checking your properties, you should start doing it in 2016. It can save you a few hours, believe me.

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

Yes, it is possible to validate Immutable.js properties thanks to react-immutable-proptypes.

High level components

Now that mixins are dead and no longer supported in ES6 component classes, we looked for a new way to do it.
What is a top-level component?

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

Simply, you are composing a new component from another and extending its behavior. You can use it in a whole bunch of situations like authentication requireAuth({ role: 'admin' })(MyComponent) (verifies the user in the top-level component and redirects if the user is not authenticated) or connect your component with a Flux/Redux store.
At RisingStack, we already like to separate data fetching and controller logic into high-level components to keep our views as simple as possible.

Test

Testing with good coverage should be an important part of your development cycle. Fortunately, the React.js community provides excellent libraries to do this.

Test components

One of our favorite libraries for testing components is e from AirBnB. With its “shallow rendering” feature, you can test the logic and rendering of your components, which is pretty awesome! This still doesn't replace selenium testing, but you take frontend testing to the next level with this tool.

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
})

It's clean, right?
Are you using the Chai assertion library? There is an integration chai-enyzime.

Test Redux

Test a reducer should be easy, it responds to incoming actions and transitions it from one state to another.

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 using asynchronous actions. To test asynchronous redux actions, we recommend looking at redux-mock-store, it can help you 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 redux test further, see the official documentation.

Use NPM

Even though React.js works fine without a packager, we recommend using Webpack ou Browserify to take advantage of the power of NPM. NPM is packed with quality React.js packages, and it can help manage dependencies in an elegant way.
(Please remember to reuse your own components, it's a great way to optimize your code)

Packet size

This question is not unique to React but since most people package their React application, I thought it was important to address it.
While you are packaging your sources, always pay attention to your package size. To keep this size as small as possible, you need to take into consideration how you define the import/require of your dependencies.
The sample code below shows two different approaches that can make a huge difference in 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';

Watch the article Reduce Your bundle.js File Size By Doing This One Thing for more details.
We also like to split our code into at least one vendor.js et app. js because updates to third-party libraries are less common than updates to your code base.
By hashing the output filenames (piece of hashes in WebPack) and hiding them for long periods of time, you can drastically reduce the size of code that needs to be downloaded for returning users to the site. Combined with lazy loading you can imagine how this can be optimal.
If you are new to WebPack, check out this great article React WebPack cookbook.

Component Hot Reload

If you've ever written a Single Page Application (SPA) with hot reload (aka livereload), you probably know how annoying it can be when you're working on a stateful component, and the whole of the page is reloaded because you have just saved in your editor. All you have to do is click again in your application, and start again with each recording, again and again...
With React, it is possible to reload a component while keeping his state – boom, no more problem!

Use ES2015

I was mentioning that we use JSX in our React.js components which we transpile with Babel.js.
Babel
Babel can do a lot more and also allows writing ES6/ES2015 code for today's browsers. At RisingStack, we use ES2015 features on the server side and client side that are available on the latest LTS version of Node.js.

Linters

Perhaps you have already used a “style guide” for your JavaScipt code but do you know that there are just as many for React? We strongly recommend that you choose one and start tracking it.
At RisingStack, we enforce running linters on the continuous integration server and on the git push Also. Take a look at the package pre push ou pre-commit.
We use “JavaScript Stand Style for JavaScript” with eslint-plugin-react to check our React.js code.
(That's right, we don't use semicolons anymore.)

GraphQL and Relay

GraphQL and Relay are relatively new technologies. At RisingStack we don't use them in production right now, we just keep an eye on them.
We wrote a library named graffiti which is a MongoDB ORM for Relay and makes it possible to create a GraphQL server from existing mongoose models.
If you want to learn these new technologies we recommend that you take a look and play with them.

What to remember from this “Best Practices” React

Many of the techniques shown and libraries are not specific to React.js. Always keep your eyes open and watch what others in the community are doing. The React community has taken a lot of inspiration from Elm architecture in 2015.

If you have an idea of ​​the essential React.js tools that all developers should use in 2016, drop us a line!

 
Paper originally written by Peter Marton CTO at RisingStack
Translated by Matthew Breton CTO at JS Republic
[separator type=”” size=”” icon=”star”] [actionbox color=”default” title=”” description=”JS-REPUBLIC is a service company specializing in JavaScript development. We are an approved training center. Find all our technical training on our partner site dedicated to Training” btn_label=”Our training” btn_link=”http://training.ux-republic.com” btn_color=”primary” btn_size=”big” btn_icon=”star” btn_external =”1″]