React Native development tools - Part 1: Linting tools

Introduction

In this tutorial series, we’re going to take a look at the following tools to improve your code and development workflow when working with React Native:

  • Part 1: Linting tools
  • Part 2: Debugging tools
  • Part 3: Component testing tools

In this part of the series, we’re going to cover the following areas:

  • Linting tools
  • Plugins for improving coding workflow

As developers, the tools that we use are very important. We use them every day to help us develop the app that we’re creating. That’s why it’s important to leverage the use of these tools so that we can be more productive and effective as developers.

Prerequisites

To effectively follow this tutorial, you need to have basic knowledge of:

  • JavaScript
  • React
  • React Native

You should also have set up your machine for React Native development. That includes Node, npm or Yarn. We’ll be specifically using Yarn to install packages in this article, so I recommend you to install it.

I’ll be using Sublime Text 3 for the examples, so I’m assuming that you know your way around the text-editor you’re using. That way, you can apply the techniques in this tutorial to the text editor of choice. I’ve done a bit of research and found out that the following text editors are supported:

  • Atom
  • Microsoft Visual Studio Code
  • Vim

Near the end of the article, I’ll be pointing out some links to help you get set up with the text editors above.

Linting tools

Linting allows you to check your code for potential errors. This process helps you improve the quality of your code, and helps enforce coding standards especially when you’re working in a team.

In order to see the linting tool in action, we’re going to create a new React Native project:

    react-native init Teslint

Once the project is created, navigate inside the Testlint folder and install the following packages:

    yarn add eslint babel-eslint eslint-config-airbnb eslint-plugin-react eslint-plugin-import eslint-plugin-jsx-a11y --dev

Note: if you don’t have Yarn installed, you can always use npm to install the packages above.

Here’s what each package does:

  • eslint - the linter to use.
  • babel-eslint - for linting babel code with ESLint. React Native uses the JSX syntax, which isn’t considered valid syntax by just plain ESLint.
  • eslint-config-airbnb - allows you to use Airbnb’s JavaScript style guide’s ESLint configuration file. The default configuration has rules for React, plugin imports, and accessibility so the following need to be installed as well:
    • eslint-plugin-react - for adding React specific rules and parser options.
    • eslint-plugin-import - adds rules for imported modules. We’ll be primarily using it to ensure that the modules we import actually exists.
    • eslint-plugin-jsx-a11y - adds rules for checking JSX elements for accessibility. We won’t really need to use this since the accessibility props used in React Native doesn’t have the same syntax as in the web. We only need to install it because the rest of eslint-config-airbnb wouldn’t work without it.

Once the above packages are installed, you can now install the SublimeLinter and SublimeLinter-eslint package for Sublime Text. If you haven’t installed Package Control for Sublime Text yet, now is a good time to do so.

You can install the packages by pressing Ctrl + Shift + P or ⌘ + Shift + P on your keyboard, select Install Package, and search for “Sublime Linter”. This should show both packages in the search results. After that, press Enter to install each plugin.

Next, open the React Native project you created earlier on the text editor. Then open the Sublime Linter settings by going to Preferences > Package Settings > SublimeLinter > Settings:

Sublime Linter Settings

That will open the default settings as well as the user settings. Edit the user settings and put the following:

1// SublimeLinter Settings - User
2    {
3      "debug": true,
4      "lint_mode": "load_save",
5    }

The debug option allows you to see debug messages in the console. lint_mode allows you to specify which instances will trigger the linting. In this case, I’ve set load_save so that the file is checked the moment it is loaded and also when it’s saved.

You can also check other options in the default settings and customize them on your user settings.

Next, create an .eslintrc file on the root of the project directory and paste the following options:

1{
2      "extends": "airbnb", // extend airbnb's JavaScript style guide: https://github.com/airbnb/javascript
3      "parser": "babel-eslint", // allows us to parse the code with babel so that jsx code won't be considered an error
4      "parserOptions": {
5        "ecmaFeatures": { // specify which additional language features to use
6          "jsx": true
7        },
8      },
9      rules: {
10        'global-require': 'off', // React Native images uses the require syntax so we're turning it off so that we don't get any errors
11        'react/jsx-filename-extension': ['error', { extensions: ['.js', '.jsx'] }], // only return an error if JSX syntax is used on files other than those with .js or .jsx file extension
12      },
13    }

Note that we’re extending Airbnb’s ESLint rules. This means we can always override the rules they specified by specifying it again under the rules object. For example, if we don’t want to require semicolons:

1rules: {
2      'semi': 0
3    }

Once the .eslintrc file is saved, you can now open one of the project files. Let’s start with the App.js file:

Test ESLint

If your text editor shows something similar to the one above, then the linter is working. If not, then it’s either you haven’t installed all the required packages or there’s an issue with your .eslintrc file. Note that you might have a different color beside each line number. For me, it’s white, it might be red for you. You should be fine as long as it shows the correct error message when you hover.

You can find out what the issue is by opening the console on your text editor. In Sublime Text, that can be done by pressing Ctrl + backtick on your keyboard. The console should give you an idea of what’s wrong. Just make a change to the code (for example, removing a semicolon) and save the file to trigger linting.

If you’re having problems getting it to work, check out the troubleshooting section near the end of this article.

Solving the issues

Once you get the linter to work, you’ll find that the App.js file has the following issues:

  • Missing trailing comma (comma-dangle)
  • ‘styles’ was used before it was defined (no-use-before-define)

Missing trailing comma

This error is triggered by Airbnb’s coding style rule that the last item on an object or array should always have a trailing comma.

This can be solved by adding a comma after View:

1import {
2      Platform,
3      Text,
4      View, // add comma here
5    } from 'react-native';

Styles was used before it was defined

no-use-before-define is a default rule implemented by ESLint. This rule prevents you from using variables that haven’t previously been defined yet.

In React Native, it’s a convention that the styles are declared after rendering the component. Though this is only true if you’re adding the styles in the same file as your component declaration.

You can solve this issue by either declaring a rule that turns it off:

1rules: {
2      "no-use-before-define": ["error", { "functions": true, "classes": true, "variables": false }], // disable the rule for variables, but enable it for functions and classes
3    }

The above rule gives you the flexibility to allow you to declare styles on the same file as the component, while still following React Native’s convention.

Another solution is to create a separate file for your styles (styles/AppStyles.js):

1import { StyleSheet } from 'react-native';
2    
3    const styles = StyleSheet.create({
4      container: {
5        flex: 1,
6        justifyContent: 'center',
7        alignItems: 'center',
8        backgroundColor: '#F5FCFF',
9      },
10      welcome: {
11        fontSize: 20,
12        textAlign: 'center',
13        margin: 10,
14      },
15      instructions: {
16        textAlign: 'center',
17        color: '#333333',
18        marginBottom: 5,
19      },
20    });
21    
22    export default styles;

You can then import the styles on your App.js file:

1import React, { Component } from 'react';
2    import {
3      Platform,
4      Text,
5      View,
6    } from 'react-native';
7    
8    import styles from './styles/AppStyles'; // import the styles

The solution above is more preferrable but it’s less flexible. It all depends on the project you’re working on.

Adding React Native specific linters

The linter we’ve used so far doesn’t really include React Native specific rules. Let’s go ahead and add them:

    yarn add eslint-plugin-react-native --dev

Let ESLint know of the plugin by editing the .eslintrc file:

1"plugins": [
2      "react-native" // add eslint-plugin-react-native as a plugin for ESLint
3    ],
4    "env": {
5      "react-native/react-native": true // whitelist all browser-like globals
6    },
7    rules: {
8      // previous rules here
9      "react-native/no-unused-styles": 2, // disallow unused styles
10      "react-native/no-inline-styles": 2, // disallow styles declared within the component itself
11      "react-native/no-color-literals": 2, // enforces variable names to be used for storing colors
12    },

Once those are added, React Native specific rules will be enforced in your project.

If you open the styles/AppStyles.js file, you’ll see the following issue:

React Native Style Rules

This issue is triggered by the react-native/no-color-literals rule that you added earlier.

To solve this, create a new colors.js file and declare all your color values in there. Declaring your color values in a separate file allows you to reuse them on another file later on. This is what the react-native/no-color-literals rule wants you to do, so you can maximize code re-use:

1// styles/colors.js
2    const containerColor = '#F5FCFF';
3    const instructionsColor = '#333333';
4    
5    export { containerColor, instructionsColor };

You can then import it from your AppStyles.js file:

    import { containerColor, instructionsColor } from './colors';

Then in your style declarations, reference the variables instead:

1container: {
2      flex: 1,
3      justifyContent: 'center',
4      alignItems: 'center',
5      backgroundColor: containerColor, // use variable instead
6    },
7    instructions: {
8      textAlign: 'center',
9      color: instructionsColor, // use variable instead
10      marginBottom: 5,
11    },

Static-typing with Flow

Flow adds static-typing features to JavaScript. Here are a couple of benefits of adding static-type checking to your project:

  • Prevent bugs that are related to incompatible data types used in function arguments, props, and state.
  • Helps in documenting your code. When you add the data type you’re expecting right in the code itself, it makes the code more readable.

When starting a new React Native project with react-native init, the project already comes with a .flowconfig file. This is the configuration file that Flow uses. We’ll still be using the new React Native project that you created earlier.

Open the .flowconfig file and update the Flow version that it’s expecting. Visit the Flow releases page and check for the latest stable version. At the time of writing of this article, it’s at version 0.73.0. Update the .flowconfig file with that version:

1[version]
2    0.73.0

Next, install that version using Yarn:

    yarn add --dev flow-bin@0.73.0

Don’t forget to check for breaking changes on the release notes (for example, options which no longer exists or updated). Then update your .flowconfig file accordingly.

Now that Flow is installed, you can now install the SublimeLinter Flow plugin.

To see Flow in action, create a helpers/add.js file and add the following code:

1// @flow
2    
3    const Add = (num1: number, num2: number) => num1 + num2; 
4    
5    export default Add;

In the code above, we’ve specified the data type that we’re expecting for each of the parameters. In this case, we’ve used number.

Next, import the helper function in App.js:

    import Add from './helpers/Add';

Then use it inside component’s render function:

    <Text>{Add(1, 2)}</Text>

The above code shouldn’t trigger Flow to return an error. But if you wrap any of the arguments in quotes:

    <Text>{Add(1, '2')}</Text>

Flow should return an error when you save the file:

Flow error: unexpected data type

If you see the above error, then Flow is working in your text editor.

There are many more Flow features which you can use, specifically for React and React Native development. But this article isn’t really meant to cover all of those, so here are a couple of articles I recommend you to check out if you want to learn more:

Code formatting with Prettier

Prettier is a code formatting tool which frees you from the hassle of manually formatting your code to match a specific style.

Here are a few code formatting instances that you usually have to do manually:

  • Adding semicolons
  • Tabs vs spaces
  • Single quote vs double quotes

Prettier does all those for you automatically. Here’s Prettier in action (note that I deliberately messed up the code formatting to emphasize what Prettier does):

Prettier in action

The first thing you need to do is install Prettier in your text editor. In Sublime Text, the name of the package is “JS Prettier”.

Next, add the Prettier tool to your project:

    yarn add prettier --dev

Next, open the Prettier config file for your text editor. In Sublime Text, you can do this by going to Preferences > Package Settings > JsPrettier > Settings - User.

Add the following and hit save:

1{
2      "debug": true, // so you can see if there's an error with Prettier
3      "auto_format_on_save": true, // auto-formats the code when you hit save on the file you're working on
4    }

Next, create a .prettierrc file at the root of your project directory and add the following. This file is similar to the .eslintrc in that it allows you to configure the default options for Prettier. Here are the rules that I have in mine:

1{
2      "singleQuote": true,
3      "trailingComma": "es5", 
4      "semi": true, 
5      "arrowParens": "always", 
6      "jsxBracketSameLine": true,
7      "bracketSpacing": true, 
8    }

Here’s what the above rules does:

  • singleQuote - always wrap strings in single quotes.
  • trailingComma - add dangling commas on objects and arrays.
  • semi - add semicolons in places where you’ve missed them.
  • arrowParens - always add parenthesis when using arrow functions.
  • jsxBracketSameLine - always put jsx's closing bracket on the same line.
  • bracketSpacing - add spaces to brackets when working with objects.

Note that these are my preferences, you can go through this page to know more about the options you can use.

Integrating Prettier with ESLint

The next thing you want to do is integrate Prettier with ESLint. That way, they will work seamlessly. You always want your Prettier config to have the same options as your ESLint config when it comes to code formatting (for example, tabs vs spaces). That way, they won’t conflict on which style to use.

But if you don’t want to deal with that, you can install the following packages on your project:

    yarn add eslint-plugin-prettier eslint-config-prettier --dev

You can then update your .eslintrc file to extend eslint-config-prettier:

1{
2      "extends": ["airbnb", "prettier"],
3    }

This disables all the ESLint rules that have to do with code formatting. For example, Airbnb’s JavaScript Style Guide requires you to use semicolons, but you’ve disabled it on your .prettierrc file:

1{
2      "semi": false,
3    }

In this case, Airbnb’s code styling rules will be disabled when you extend the prettier config so ESLint will no longer complain even if you don’t have semicolons in your code.

For cases where you don’t want to disable all the code styling rules, you can use the special rules provided by the plugin to enable them.

Troubleshooting

This section aims to solve issues that you’re having in getting the tools to work. The techniques mentioned in this tutorial was tested on Mac, Ubuntu, and Windows machines. Below are the issues that I’ve personally encountered:

  • Node not detected
  • Issues are not indicated

Node not detected

If you’re like me, and you’re using nvm for managing the Node versions installed on your machine, you will most likely have problems in getting the three tools to work.

The first step, is to determine the Node version you’re using. Copy the path that it points out because this will be the one that you’ll be using to specify the Node path:

    which node

Next, list the Node versions that are currently installed:

    nvm list
nvm list

Set the default to which ever the currently used version is:

    nvm alias default v6.10.3

To fix Prettier, go to Preferences > Package Settings > JsPrettier > Settings - User. From here, you can add the node_path:

1{
2      // previously added settings
3      "node_path": "/Users/YourUsername/.nvm/versions/node/v6.10.3/bin/node"
4    }

To fix ESLint and Flow, go to Preferences > Package Settings > SublimeLinter > Settings and add the following:

1{
2      // previously added settings
3      "linters": {
4        "eslint": {
5          "env": {"PATH": "/Users/YourUsername/.nvm/versions/node/v6.10.3/bin/"}
6        },
7        "flow": {
8          "env": {"PATH": "/Users/YourUsername/.nvm/versions/node/v6.10.3/bin/"}
9        },
10      }
11    }

That should fix the issue with Prettier and SublimeLinter not being able to detect the location to your Node version.

Don’t forget to restart your text editor after applying the fix if it doesn’t work immediately.

Issues are not indicated

If you’re on Mac or Ubuntu, you will most likely have this problem after restarting your machine a couple of times. Not sure why, but this issue doesn’t occur if you’ve just set up your machine with the tools mentioned above.

If the ESLint and Flow issues are not being indicated beside each line number, then your problem is most likely that ImageMagick isn’t installed on your system. SublimeLinter requires ImageMagick to add the colors beside the line numbers.

On Mac, the easiest way to install ImageMagick is via homebrew:

    brew install imagemagick

On Ubuntu, you can install it via apt:

    sudo apt-get install imagemagick

Don’t forget to restart your text editor after applying the fix.

Setting up other text editors

As promised, here are some articles which will help you get set up with ESLint, Flow, and Prettier on other text-editors:

Conclusion

That’s it! In this tutorial, you’ve learned how to use ESLint, Flow, and Prettier when developing React Native apps. Always remember to check which tools are available to make your life easier when coding.