Pro tips for setting up a React Native project in 2020
Tags: react, reactnative, javascript
Published: 2020-10-21 12:15:05

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/95y6hdv1nnjc4w1ou81h.jpeg)

*Originally published at [Medium](bit.ly/2TeLA0Y)*

# Introduction

The year is 2020 and mobile development is still in an upturn. *For smaller businesses native mobile development is not an option most of the time because it requires a lot of time and developer resources so it is not cost effective enough*. Luckily, React Native, Facebook's mobile cross platform development tool have improved a lot in the past years and it can be a viable option instead of pure native mobile development.

In this article I will discuss the following topics:
- *Motivation*
- *Project bootstrapping*
- *Initial directory and file changes*
- *Explicit build tool and dependency versions*
- *Code formatting and linting*
- *Absolute imports and modularization*
- *Grouped exports*
- *Final thoughts*

# Motivation

Personally, I like to plan ahead, I'm convinced that if a project builds on a solid base then it will stand the test of time. Whenever I start working on a project, I always assume it is a long running one, meaning I try to prepare for whatever might happen but without being prophetic.

As at [Supercharge](https://supercharge.io/) I had the opportunity to successfully ship multiple React Native projects and support them for years in production, I would like to share with you some tips on how I would bootstrap a new React Native project nowadays.

# Prerequisites

Other than the [React Native requirements](https://reactnative.dev/docs/environment-setup), I recommend installing Node Version Manager ([MacOS](https://github.com/nvm-sh/nvm), [Linux](https://github.com/nvm-sh/nvm), [Windows](https://github.com/coreybutler/nvm-windows)), NodeJS 8.17.0 or newer, Node Package Manager 5.2 or newer, and [Visual Studio Code](https://code.visualstudio.com/) with [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) and [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) extensions.

# Project bootstrapping

I always use the [React Native CLI](https://github.com/react-native-community/cli) to create a new React Native project, because *in the long term there's a great chance that I have to write some native (Android, IOS) code*.

So let's create our new React Native project called *MyApp*:

```
npx react-native init MyApp --template react-native-template-typescript --npm
```

- **[NPX](https://medium.com/@maybekatz/introducing-npx-an-npm-package-runner-55f7d4bd282b) is a package runner for NPM**, and it's available since NPM 5.2. *With NPX there's no need to install the 'react-native-cli' package globally* just to initialize our project.
- The **'--template react-native-template-typescript'** parameter will *use the Typescript template to create the project*. I always use Typescript for static type checking, it will make things more developer friendly and less prone to errors.
- The **'--npm'** parameter will make the project *use NPM instead of Yarn to install initial dependencies*.

# Initial directory and file changes

I like to move all of the project javascript **source files to an 'src' directory** to keep the project root nice and tidy. Then I **move the 'App.tsx' file from the project root to the 'src' directory**. Finally, because we're using Typescript in the project, I **rename the 'index.js' file to 'index.ts'**.

# Explicit build tool and dependency versions

It's important to make project builds repeatable, no matter where the project is built (CI, other developer's machine). That's why I like to use explicit build tools, package manager and dependency versions wherever possible.

To use **explicit Node and NPM versions**, some changes need to be made:

Update **package.json** file with 'engines' block:

```
"engines": {
  "node:": "x.y.z",
  "npm": "a.b.c",
}
```
- Where **"x.y.z"** is the **explicit Node version** you want to use (Eg: "12.16.1")
- Where **"a.b.c"** is the **explicit NPM version** you want to use (Eg: "6.13.4")

Create a **.npmrc file in the project root directory** with the following content:

```
engine-strict=true
save-exact=true
```
- The '**engine-strict=true**' line will make *NPM look for allowed version defined in the "engines" block* when I am trying to install dependencies
- The '**save-exact=true**' line will make *NPM install explicit dependency versions*. You're correct to think that's why we have the 'package-lock.json' file, but I like to see explicit dependency versions in the package.json file as well.

# Code formatting and linting

The **consistent code style** is really important when multiple developers contribute to the project. *To make code formatting become nothing to worry about, I use Prettier, which takes the burden off my shoulders*.

There's a **'.prettierrc.js' file in the project root** already, but we can customize it further. In my case I use the following Prettier config:

```
module.exports = {
  tabWidth: 2,
  useTabs: false,
  printWidth: 140,
  semi: true,
  trailingComma: 'es5',
  bracketSpacing: true,
  arrowParens: 'always',
  singleQuote: true,
  jsxSingleQuote: true,
  jsxBracketSameLine: true,
};
```

To **make code formatting an automatic task on save**, I populate the workspace config file of Visual Studio Code (**.vscode/settings.json**) with the following content:

```
{
  "editor.tabSize": 2,
  "editor.formatOnSave": false,
  "[javascript]": {
    "editor.formatOnSave": true
  },
  "[typescript]": {
    "editor.formatOnSave": true
  },
  "[javascriptreact]": {
    "editor.formatOnSave": true
  },
  "[typescriptreact]": {
    "editor.formatOnSave": true
  },
  "typescript.tsdk": "node_modules/typescript/lib"
}
```

As **I prefer single quotes** in the source files, I **add rule override to the '.eslintrc.js'** file to not to warn me about single quotes:

```
module.exports = {
  root: true,
  extends: '@react-native-community',
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint'],
  overrides: [
    {
      files: ['*.js', '*.ts', '*.jsx', '*.tsx'],
      rules: {
        'jsx-quotes': 0,
      },
    },
  ],
};
```

As a final step, I **add linting scripts to the package.json file**:

```
"scripts": {
  "lint:style": "prettier --check 'src/**/**.{js,ts,jsx,tsx}'",
  "lint:code": "eslint src/ --ext .js,.jsx,.ts,.tsx",
  "lint": "npm run lint:style && npm run lint:code",
  "test": "jest",
  "sanity": "npm run lint && npm run test"
}
```

# Absolute imports and modularization

I don't like *long relative imports* when I'm deep in the directory tree. It *makes refactoring circumstantial*. In order to avoid this, I always **modularize the codebase based on some logic** and **use absolute imports** in the source files.

First, let's create the following directory and file structure:

```
src/
  app/
    App.tsx
    package.json
  core/
    package.json
  ui/
    package.json
```

**By creating package json files in the sub directories, I define sub-modules**. Let's populate the contents of the package.json files:

**src/app/package.json**
```
{
  "name": "app"
}
```

**src/core/package.json**
```
{
  "name": "core"
}
```

**src/ui/package.json**
```
{
  "name": "ui"
}
```

**To be able to use absolute imports, I need to update the tsconfig.json file in the project root:**
```
{
  "compilerOptions": {
    "baseUrl": "./src",
  }
}
```

After these changes **we can use import statements the following way**:

**src/app/App.tsx**
```
import { Row } from 'ui/component/layout/Row.component.tsx'
import { someExportedUtilMethod } from 'core/util/utils.ts'
```

**To avoid circular imports and keep the separation of concerns intact, there are some important rules to pay attention to:**
- Files under any sub-module directory should use relative imports when importing from files under the same sub-module directory
- Files under the 'app' directory should import from files under the 'app', 'core' and 'ui' directories
- Files under the 'core' directory should only import from files under the 'core' directory
- Files under the 'ui' directory should import from files under the 'ui' and 'core' directories

# Grouped exports

When **named exports are used instead of default exports, they can be grouped in index files** which then can be used to **import the named exports from**. The advantage of this is that *files can be moved freely under a given root directory and there is no need to update every single source file where these files are used to import from*.

First, I have the following directory and file structure:

```
src/
  app/
    App.tsx
    package.json
  core/
    package.json
  ui/
    component/
      button/
        index.ts
        FlatButton.component.tsx
        RaisedButton.component.tsx
      layout/
        index.ts
        Column.component.tsx
        Row.component.tsx
      index.ts
    package.json
```

**src/ui/component/button/index.ts**
```
export * from './FlatButton.component';
export * from './RaisedButton.component';
```

**src/ui/component/layout/index.ts**
```
export * from './Column.component';
export * from './Row.component';
```

**src/ui/component/index.ts**
```
export * from './button';
export * from './layout';
```

After I've populated the index files, I can use imports the following way:

**src/app/App.tsx**
```
import { Column, FlatButton, RaisedButton, Row } from 'ui/component';
```

**This way I don't have to explicitly define the path for the import**, *I can move the components under the component directory freely*, I only have to update the related index files.

# Final thoughts

I hope this bootstrapping guide will be helpful for you in the future when starting a new React Native project.

*Remember, nothing is written in stone, these are just suggestions based on my own experience with React Native.*

Thanks for reading it through, I welcome any feedback regarding this topic.

---

*At [Supercharge](https://supercharge.io/), we are a next-generation innovation agency working with our clients to create transformative digital solutions. If you liked this article, check out some of Supercharge's other articles on our [blog](https://supercharge.io/blog), or follow us on [LinkedIn](https://www.linkedin.com/company/teamsupercharge/), and [Facebook](https://www.facebook.com/TeamSupercharge). If you're interested in open positions, follow this [link](https://supercharge.io/jobs).*