React Boilerplate: Everything you need to quick-start a new React project inside one repo
Published: 2021-04-12 19:49:34

When creating a new React project, I faced the same problems every time. I need to build it manually because `create-react-app` do not provide everything that we use in real projects. We need to set up data storage, routing, configure REST, styles, etc. This was quite time-consuming, and our team decided to create some boilerplate to quick-start new projects. We’re starting to develop boilerplates for different use cases. In this article, I want to present my work to you: a boilerplate for a `React` application.

[![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q5zc6nd63a8kyt0qe6bb.png)](https://github.com/maddevsio/react-madboiler?utm_source=devto&utm_medium=react-boiler)
 

##Technology Stack
Here’s a list of libraries and dependencies used for this boilerplate. We’d decided to use minimal dependencies, and you can add anything if you need.

1. React-router-dom: Declarative routing for React.
2. Styled-components: Use the best bits of ES6 and CSS to style your apps without stress. The best CSS-in-JS library for React.
3. React-use: Some very simple and useful hooks for components that you can build amazing things with.
4. Prop-types: Runtime type checking for React props and similar objects.
5. Axios: The best promise-based HTTP client for Javascript.
6. Jest: Delightful JavaScript Testing Framework with a focus on simplicity.
7. Testing-library: Simple and complete testing utilities that encourage good testing practices.
8. ESLint+Prettier: Linter to find and fix problems in your JavaScript code. Prettier for code formatting.

##First start

###Using docker and docker-compose
This option is good in that you don’t need to install a lot of dependencies on your working device. Docker just encapsulates all that trash.

To start the project with this option, you need to install [Docker](https://docs.docker.com/get-docker/) and [docker-compose](https://docs.docker.com/compose/install/)

Then, you just need to run the following command:

`yarn docker:dev`
When Docker installs all the necessary dependencies and builds your application, you will see Compiled successfully in your console. Your project is available on 3000 port; you can open it and start developing http://localhost:3000

###Using npm

If you can’t or don’t want to use docker, you can use the default method for starting your project using [Node.JS and npm(yarn)](https://nodejs.org/en/)

1. Install dependencies

`yarn # or npm i`

2. Start the project

`yarn start # or npm start`

The application is available at http://localhost:3000

###Routing
We use [react-router-dom](https://reactrouter.com/web/guides/quick-start) for routing in the application. All the routes are stored in the `src/Router.jsx` file.
```
import React from 'react'
import { Route, Switch } from 'react-router-dom'
// pages
import { Main, Todo } from './pages'
function Router() {
  return (
    <Switch>
      <Route exact path='/' component={Main} />
      <Route exact path='/todo' component={Todo} />
    </Switch>
  )
}

export default Router
```

##Adding a new route
To create a new route, you need to do the following steps:

`1.Create the new file in the src/pages folder`
`2.Add the new created page in the src/pages/index.js file for better importing.`
`3.Add the new page in src/Router.jsx file`

####Additional information
* [Documentation](https://reactrouter.com/web/guides/quick-start)
* **Important**: The pages are used only to logically separate different parts of the application. You don’t need to use the pages as components. You can use [react-helmet](https://www.npmjs.com/package/react-helmet) to set up the page’s meta-tags (title, description, etc.)

##Components
When you work with the components, it’s recommended to use a modern approach with functional components and hooks.

**It’s not recommended to use class components because they work too slowly (performance) and won’t be supported**

To create the component, you can use the following `CLI-script`:

`yarn create:component MyComponent`

After using this script, the folder with your component’s name will appear in your `src/components` folder. In this case, it will be the `src/components/MyComponent` folder.

###Component’s files description
**index.jsx**— core file with logic. Example:
```
import React, { useState } from 'react'
import { useMount, useUpdateEffect } from 'react-use'

// view
import TodoList from './TodoList'

function Wrapper() {
  const [todos, setTodos] = useState([])

  const getInitialTodos = () => {
    // ...some logic to get initialTodos from localStorage
  }

  const saveTodos = () => {
    // ...some logic to save todos from localStorage
  }

  const addTodo = todo => setTodos([...todos, todo])
  const removeTodo = todo => setTodos([...todos.filter(todo => todo === todo)]);

  // Use mount-hook for calling getInitialTodos() after mount
  useMount(() => getInitialTodos())

  // Watch todos and save it in localStorage after updating
  useUpdateEffect(() => saveTodos(), [todos])

  // return view with some props
  return <TodoList todos={todos} addTodo={addTodo} removeTodo={removeTodo} />
}

export default Wrapper
```

`[ComponentName].jsx` — view file(markup). Example:
```
import React from 'react'
import PropTypes from 'prop-types'

import TodoItem from '../TodoItem'

// prop-types
const propTypes = {
  todos: PropTypes.arrayOf(PropTypes.object),
}

function TodoList({ todos }) {
  if(!Boolean(todos.length)) return <div className="empty">No todos :)</div>
  return (
    <div className="todo-list">
      {todos.map(todo => <TodoItem key={todo.id} todo={todo} />)}
    </div>
  )
}

TodoList.propTypes = propTypes

export default TodoList
```

`[ComponentName].test.jsx` — unit tests

`[ComponentName].styles.js`— styles (styled-components by default)

###Useful links
* [PropTypes](https://reactjs.org/docs/typechecking-with-proptypes.html)
* [Hooks](https://reactjs.org/docs/hooks-intro.html)

###LocalStorage
To work with localStorage you can use additional utilities: `loadState` and `saveState Example`:

```
import { saveState, loadState }  from '../utils/localStorage'
const save = data => saveState(data, 'key')
const load = () => loadState('key')
```

##Hooks
To build logic within components, people usually use hooks.

###React-use
This is a library of additional react hooks that meet most of the needs so that you do not have to reinvent the wheel every time. [All hooks list](https://github.com/streamich/react-use)

Most useful hooks:

* [useDebounce](https://github.com/streamich/react-use/blob/master/docs/useDebounce.md) — for use debounce effect in the component
* [useLocalStorage](https://github.com/streamich/react-use/blob/master/docs/useLocalStorage.md) — for working with localStorage in the component
* [useMount](https://github.com/streamich/react-use/blob/master/docs/useMount.md) — mount lifecycle hook
* [useUpdateEffect](https://github.com/streamich/react-use/blob/master/docs/useUpdateEffect.md) — update lifecycle hook
* [usePrevious](https://github.com/streamich/react-use/blob/master/docs/usePrevious.md) — store prevState or prevProps
* [useBoolean](https://github.com/streamich/react-use/blob/master/docs/useToggle.md) — simple state hook for boolean values
* [useList](https://github.com/streamich/react-use/blob/master/docs/useList.md) — state hook for store arrays with additional utilities

####Custom hooks
Creating custom hooks is a very useful thing as it allows reusing large amounts of code. If you see code that will probably be reused in the future, hook it. This is an example of using a simple custom hook implementing work with API:
```
import { useState } from 'react'
import { useList, useToggle } from 'react-use'

import fetchImages from './fetchImages'

const useFetchImages = ({ source }) => {
    const [images, imagesActions] = useList([])
    const [isLoading, toggleLoading] = useToggle(false)
    const [error, setError] = useState(null)
    
    const fetchImages = async () => {
        toggleLoading(true)
        try {
            const data = await fetchImages(source)
            imagesActions.set(data)
        } catch(err) {
            setError(err)
        }
        toggleLoading(false)
    }
    
    return {
        images,
        isLoading,
        error,
        fetchImages,
    }
}

export default useFetchImages
```
##Utilities
Utilities are stored in the `src/utils` folder in separate files.

###Available utilities
* `camelToSnakeCase` and `snakeToCamelCase`— transformation of a string into various styles of writing phrases without spaces or punctuation
* `normalizeObjectKeys` — transformation of all the object field keys using `snakeToCamelCase`
* `normalizeCollectionKeys` — transformation of all the elements(Element should be an object) of the array using `normalizeObjectKeys`
* `getRequestParams` — function for getting values of get-parameters from `location.search`
* `localStorage` — utilities for working with localStorage

##Axios
In working with API requests, the most useful library is [axios](https://github.com/axios/axios with `async/await` syntax).

###Configuration
`Axios` configuration is in the `src/config/api.js` file.

###Additional function setApiHeader
If you need to add a header in the existing axios instance, you can use `setApiHeader` function. Example:
```
import { setApiHeader, api } from '../config'

async function authenticate() {
  // Authorization
  const response = await api.post('/auth')

  // Getting token from response
  const { token } = response

  // Set header for the next authenticated requests
  setApiHeader('Authorization', `Bearer ${token}`)
}

authenticate()
```

>Always try to use async/await syntax.

###Environment variables
To work with environment variables, we need to use some config files:

* `.env.example` — for storing examples of variables
* `.env` — for variables
To add a new environment variable, you need to do the following steps:

1. Add variables into `.env.example` file with empty value
```
REACT_APP_API_BASE_URL=
```
2. Add variable with value int `.env` file.
```
REACT_APP_API_BASE_URL=https://google.com/api
```
3. Restart the project (required)

4. Add the variable into the config (`src/config/index.js`) and use it from config

```
export const config = {
  API_URL: process.env.REACT_APP_API_BASE_URL,
}

axios.get(config.API_URL)
```
>Don’t forget to restart the project after adding/updating any >variables
>
>Environment variables should be ALWAYS started by REACT_APP_ ; otherwise, they won’t work

##Styles
To write styles, we can use several approaches:

* Scss/BEM — default styling
* Css-In-JS ([styled-components](https://styled-components.com/docs/advanced#theming)) — a recommended option that is simpler and more convenient than the previous one.

###Testing
In testing everything, `Jest` and `React-testing-library` are used.

###Useful links
* [Jest](https://jestjs.io/docs/en/getting-started)
* [Testing-library](https://testing-library.com/)
* [React-testing library](https://testing-library.com/docs/react-testing-library/intro)

###Unit-tests running
There are several scripts to run tests:

* `yarn test` — watch-mode
* `yarn test:coverage` — watch-mode+coverage
* `yarn test:ci` — without watch-mode + coverage + disable coloring output

###Coverage
Coverage generates after running yarn `test:coverage command.` You can see expanded coverage in the HTML format in the `./coverage` folder.

>Unit tests also have a minimal coverage threshold. If coverage is less than 80%, the tests will fail

##Formatting
Linters are to keep code clean. They prevent shitcode from getting into a repository.

###ESLint
[ESLint](https://eslint.org/) is used for linting Javascript code.

[Airbnb](https://www.npmjs.com/package/eslint-config-airbnb) config is used as default.

To run a linter, you can use the following npm-scripts:

`yarn lint:js` —to run a linter

`yarn lint:js:fix` —to run a linter with autofix

###CSS(styled-components)
To lint css code, [stylelint](https://stylelint.io/) is used. The linter checks your code for typos and spelling mistakes. To run the linter, you can use `yarn lint:css` script

Find out how best to use SASS extensions for custom CSS variables [here](https://maddevs.io/blog/how-to-make-better-use-of-sass-extensions-for-custom-css-variables/).

###Airbnb styleguide links
[Javascript](https://github.com/airbnb/javascript)
[React](https://github.com/airbnb/javascript/tree/master/react)

>To run both linters, you can use yarn lint:all script

##JSDoc
The optimal solution to make your code more readable and cleaner is to use JSDoc. The project doesn’t use JSDoc by default, but you can easily add it using the following helpful links:

* [Documentation](https://jsdoc.app/)
* [Eslint-plugin](https://www.npmjs.com/package/eslint-plugin-jsdoc)

##Running in production
To run the project in production, you can use yarn docker:prod script. This script does the following steps:

* Download dependencies
* Build the project
* Run nginx to serve static content

##Cypress
Cypress is a framework for end-to-end testing based on Javascript.

###Why Cypress?
You can have 100% code coverage with unit tests, which test all your components separately, but your application can still fail when the components start to interact with each other. To prevent possible fails, you need to use e2e tests with Cypress. Cypress can test everything that works in a browser. To install `cypress`, you can use [the instructions](https://github.com/maddevsio/react-madboiler#cypress) in the [`readme`](https://github.com/maddevsio/react-madboiler).

##Typescript
To develop modern, big `React` applications, people most often use `Typescript` to prevent unexpected errors and problems. `Typescript` helps avoid primitive errors and makes `Javascript` clearer and more expressive. `Typescript` has its disadvantages, but the benefits most often outweigh them. If you want to use `Typescript` along with our boilerplate, you can use [the instructions](https://github.com/maddevsio/react-madboiler#how-to-add-typescript) for adding it to a project in [`readme`](https://github.com/maddevsio/react-madboiler).

##Gitlab CI
[Gitlab CI](https://docs.gitlab.com/ee/ci/) is one of the easiest and most convenient tools to check and deploy your code anywhere. In our boilerplate, we use several steps to make it easy to deliver your code to production:

* `install` — installing dependencies using `yarn`
* `lint` — code linting `yarn lint:all`
* `test` — running unit tests using yarn `test:ci script;` building and **displaying** coverage
* `pages` — building the project `yarn build`
* `pages:deploy` — deploy to gitlab-pages

##Additional tricks
Here, I’ve collected a few tricks to make the development of your app easier and faster.

###CLI
To create the component, you can use the following `CLI-script`:
```
yarn create:component MyComponent
```

When you use this script, a folder with your component’s name will appear in your `src/components` folder. In this case, it will be the `src/components/MyComponent` folder.

####VSCode-snippets
Here is a list of available snippets to quickly create some entities:

* `mdocmp` — component
* `mdstyle` — styled-components file
* `mdcompunit` — unit tests for component
* `mdpage`— page
* `mdhook` — custom hook
These snippets are automatically available in your `VSCode` because they are set up for the project. You can see and edit any snippet in the `.vscode/madboiler-snippets.code-snippets` file

####Useful VSCode extensions
Here’s a list of the most useful VSCode extensions that make developing your `React` application easier and faster:

* `vscode-styled-components` — styled-components support
* `Visual Studio IntelliCode` — intelliSense for VSCode (AI-assit)
* `TODO Highlight` — highlight your #todos
* `React PropTypes Intellisense` — intelliSense for PropTypes
* `Prettier` — for autoformatting
* `Path Intellisense` — intelliSense for ES6 imports/exports
* `ESLint` — lint highlight

##Сonclusion
This article shows you the boilerplate that we actively use when creating new projects. The boilerplate includes everything you need and describes some additional useful things (such as typescript and cypress). Feel free to use our boilerplate, and if you have any questions or problems with it, we promise to help you. Thanks for reading!

Previously published at [maddevs.io](https://maddevs.io/blog/amazing-template-for-react-application/?utm_source=devto&utm_medium=react-application)