Organizing Your React App Into Modules
Tags: react, organization, projectorganization
Published: 2019-06-02 19:47:24

---
title: Organizing Your React App Into Modules
published: true
description: 
tags: react, organization, project organization
---

First time poster here, long time reader. Figured it was time to give back.

The last two years of my eight years in software development I've done React development. Coming from vanilla Javascript and jQuery, let me say - I'm in love.

This post will detail how we've been organizing our React apps.

This post also assumes you already know how to setup and use React (I.E. this isn't a getting started post).

Let's get to it!

## Intro

I'm tired of todos - so our fictional shell app is a bug tracker for game studios to allow alpha and beta testers to report bugs.

It has four modules: Dashboard, Games, Users, Analytics.

![Screenshot of fictional app](https://github.com/jackjwilliams/dev-react-modules/raw/master/dev-react-modules-screenshot.png)

The beauty of this approach is the parent app has no specific knowledge of the child modules. All it knows is it *has* modules. Each module manages its own placement and data. You don't have to add `<Route />` or `<Link></Link>` anywhere in the parent App - the children define this.

The code for this post is on GitHub.

{% github jackjwilliams/dev-react-modules %}


## Getting Started

Let's get to some actual coding!

If you don't have create-react-app, install it with `npm install -g create-react-app`. Then ...

`create-react-app dev-react-modules`
`cd dev-react-modules`
`npm install react-router-dom --save`
`yarn start`

I won't detail the styling applied, you can view that in the [GitHub repo](https://github.com/jackjwilliams/dev-react-modules).

## Create Modules

Under the src folder, we start out by creating our module structure. It looks something like this:

* modules
  * Analytics
  * Dashboard
  * Games
  * Users

In each module's folder, add an index.js

### src\modules\Analytics\index.js

```jsx
import React from 'react';

const Analytics = () => (
    <div>Analytics Module</div>
);

export default {
    routeProps: {
        path: '/analytics',
        component: Analytics
    },
    name: 'Analytics',
}

```

### src\modules\Dashboard\index.js

```jsx
import React from 'react';

const Dashboard = () => (
    <div>Dashboard Module</div>
);

export default {
    routeProps: {
        path: '/',
        exact: true,
        component: Dashboard,
    },
    name: 'Dashboard',
};

```

### src\modules\Games\index.js

```jsx
import React from 'react';

const Games = () => (
    <div>Games Module</div>
);

export default {
    routeProps: {
        path: '/games',
        component: Games,
    },
    name: 'Games',
};

```

### src\modules\Users\index.js

```jsx
import React from 'react';

const Users = () => (
    <div>Users Module</div>
);

export default {
    routeProps: {
        path: '/users',
        component: Users,
    },
    name: 'Users',
};

```

Nothing too fancy here, we've created our modules and their default exports. But instead of *only exporting a component* - leaving the parent to orchestrate things - we export **everything needed for the module to exist**. This could be expanded to include the module theme, navigation icon, required permission(s), etc...

What I like about this is that I don't have to change the parent to add a module. I just ... add a module. 

Let's break the export down, I've added some comments below.

```javascript
export default {
    routeProps: { // This gets passed straight to react-router
        path: '/users', // Where the module lives in the nav hierarchy
        component: Users, // The actual component itself
    },
    name: 'Users', // The name of the module
};
```

You can think of the export structure like a contract between the parent and child module. The parent says I don't care how many modules I have, I just need these things to render you.

Now we need to export all these modules. In the modules folder, create an index.js.

### src\modules\index.js

```javascript
import Analytics from './Analytics';
import Dashboard from './Dashboard';
import Games from './Games';
import Users from './Users';

export default [
    Dashboard,
    Analytics,
    Games,
    Users
];
```

Here we are exporting a *list* of modules. Which is all the parent needs.

## Create Parent App

Now that our child modules are all complete, let's bring it all together in the main App.js.

### src\App.js

```jsx
import React from 'react';
import { useState } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import logo from './logo.svg';
import './App.css';

import modules from './modules'; // All the parent knows is that it has modules ...

function App() {
  const [currentTab, setCurrentTab] = useState('dashboard');

  return (
      <Router>
        <div className="App">
          <header className="App-header">
            <img src={logo} className="App-logo" alt="logo" />
            <ul className="App-nav">
              {modules.map(module => ( // with a name, and routes
                  <li key={module.name} className={currentTab === module.name ? 'active' : ''}>
                    <Link to={module.routeProps.path} onClick={() => setCurrentTab(module.name)}>{module.name}</Link>
                  </li>
              ))}
            </ul>
          </header>
          <div className="App-content">
            {modules.map(module => (
              <Route {...module.routeProps} key={module.name} />
            ))}
          </div>
        </div>
      </Router>
  );
}
```

Let's break it down.

`import modules from './modules';`

Like I said before, all the parent needs to know is it has modules. Here, we import them. 

```jsx
<ul className="App-nav">
  {modules.map(module => (
      <li key={module.name} className={currentTab === module.name ? 'active' : ''}>
        <Link to={module.routeProps.path} onClick={() => setCurrentTab(module.name)}>{module.name}</Link>
      </li>
  ))}
</ul>
```

Here, the parent knows that the module has a name and a link (because it's a contract, remember?), so it can dynamically build the navigation menu.

```jsx
<div className="App-content">
  {modules.map(module => (
    <Route {...module.routeProps} key={module.name} />
  ))}
</div>
```

Here, the parent also knows the module has a route with a component, so it can dynamically render the `<Route />`'s.

And now you have a self organizing, modularized React application. 

But wait, there's more!

## Adding New Modules

We left out one critical module for our bug tracker: Bugs.

The beauty of our new structure is that all I have to do is add a new module to the export list.

### src\modules\Bugs\index.js

```jsx
import React from 'react';

const Bugs = () => (
    <div>Bugs Module</div>
);

export default {
    routeProps: {
        path: '/bugs',
        component: Bugs,
    },
    name: 'Bugs',
};

```

### src\modules\index.js

```javascript
import Analytics from './Analytics';
import Bugs from './Bugs'; // added
import Dashboard from './Dashboard';
import Games from './Games';
import Users from './Users';

export default [
    Dashboard,
    Games,
    Bugs, // added
    Users,
    Analytics,
];

```

## Conclusion

I've been using this structure for a couple of years now and love it. It's expanded quite a bit in our application, but I wanted to keep this post simple.

Also I can't take credit for this. When starting out a couple of years ago with React, I was lucky enough to work with a senior React pro. He taught me this structure (and continues to teach me good React practices). I love learning things from other developers!

Thoughts, questions, suggestions? How do you organize your React projects?