Introduction

In this post, I will show you some suggestions for structuring and organizing the front end of your app. Whenever I start working on a project, I like to scaffold it with some files and folders. The create-react-app cli is a good starting point. However, it only provides the bare minimum for what I would need to create a project.

I will always need to add files and folders. However, if I start coding without some direction for how the app will grow, it usually ends up a mess for me. As soon as I realize it would be better to group certain files in their own folder, I start to feel the pain. All references to the files have to be changed, and the project has to be rebuilt. There are editors that can take care of this kind of refactoring, but that is not the case with mine.

I like a neat work environment and establishing some order up front greatly improves the development experience. The solutions I have come up with stem from style guides and other React apps I have seen. The examples are tailored for business applications whose primary purpose is to serve content.

Planning

If you are responsible for building the entire application, I think it is a good idea to design the API first. If someone else is developing the API, it is good to communicate with them about the API. Knowing what the data and endpoints will be can guide the organization of the app's content and consequently the views.

In my opinion, the data should direct the development of the app. How can we design a view for someone if we don’t know what information we want to communicate to them? The API does not have to be implemented yet; we just need to know what the endpoints will be. Let’s look at an example API for a blog app that lets users post articles. These are the resources:

  • All users - /users
  • A user with the id userId - /users/:userId
  • All user posts - /users/:userId/posts
  • All posts - /posts
  • All posts with the id postId - /posts/:postId
  • All post comments - /posts/:postId/comments
  • All comments - /comments
  • All comments with the id commentId - /comments/:commentId
  • All replies of a comment - /comments/:commentId/replies

The next thing to think about is what to do with this information — specifically, how you are going to display it. Now is the time I will decide what the pages will be. A page is the highest level component I want to use for organizing the content. Each endpoint does not have to correspond to a page or a view. This will serve as a guide for the ingredients we have to work with. These are the pages we will use for the blog:

  • Home page
  • Users page
  • User page
  • Dashboard page
  • Posts page
  • Post page

Page components will be composed of other components and linked to your routes.

Organizing the Project

It is best to make the app as modular as possible. That way components can be added and subtracted easily. This is an example of how to organize your directory:

Project/
  |-public
  |-src
    |-index.js 
    |-index.scss
    |-constants.js
    |-App.js
    |-Routes.js
    |-components/
      |-Comments/
      |-Posts/
      |-Users/
        |-UserList/
        |-UserItem/
    |-includes
    |-layouts/
    |-pages/
    |-sass/
      |-mixins
      |-variables
      |-colors
   |-static/

Your app entry point will be index.js. This will be solely responsible for rendering the routes component. It can also be thought of as the place the app gets bootstrapped.

import React from 'react';
import ReactDOM from 'react-dom';
import Routes from './Routes';

ReactDOM.render(
    <Routes />, 
    document.getElementById('root')
);

I have seen where the route component is created in this component. However, the routes are a component and components should be defined in their own files. The Routes component will be responsible for configuring all of the app's routes and importing the used components. Here is a router with a few of our routes defined:

import React from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import HomePage from './pages/HomePage';
import PostsPage from './pages/PostsPage';
import PostPage from './pages/PostPage';

function Routes() {
  return (
    <Router>
      <div>
        <Route exact path='/' component={HomePage} />
        <Route exact path='/posts' component={PostsPage} />
        <Route path='/posts/:id' component={PostPage} />
      </div>
    </Router>
  )
}

export default Routes;

If there were many sub-routes, you might consider storing them in their own directories. Whenever a file or directory is growing too large, see if the information can be moved to another file or directory.

Organizing the Views

Pages have similar features that can be abstracted away. The presentation of the page can be separated from the main content of the page. All the pages will have at least a header and footer. Instead of repeating those components in every page component, we can take them out and put them inside of a layout component. The layout is a container for our component. The App component will be used as the container for the layout of our pages. If you wanted to use other layouts, you could put them in a layouts folder. This is our App component:

import React, { Component } from 'react';
import Header from './includes/Header';
import Footer from './includes/Footer';

class App extends Component {
  render() {
    return (
      <div>
        <Header />
          { this.props.children }
        <Footer />
      </div>
    );
  }
}
export default App;

This component could be given a different name that better describes its purpose. However, I am using the name App because I consider it the root component for building all other components. The Header and Footer components are kept in an includes folder because this is for reusable templates or views that will be used for building the layouts. Components like a form or button would not be kept here. Our page components will use the app component. This is a simple version for the posts page component:

import React from 'react';
import App from '../App';
import PostList from '../components/Post/PostList';

function Posts(props) {
  return (
    <App>
      <PostList />
    </App>
  )
}

export default Posts;

PostList is a component that will live in our components directory. Each component should further be saved to a subdirectory in an index.js file. This is so any files related to a component can be grouped together. These files can include css partials and test files. If you are using a css preprocessor like Sass or Less, all of the partials can be imported into a main file. Furthermore, you can have a folder for Sass that includes partials for variables and mixins.

The compiled output for your css can be saved to the static folder. A static folder will contain your static assets like images, fonts, and any other resources global to your app. Finally, you will need a directory for the build and your end-to-end tests.

Conclusion

The kinds of components you use in your application is just as important as what components. Organizing views by layouts, pages, and functional components separates our concerns and keeps components small. This article does not cover all of the parts of a React app like creating models for our data or services for the APIs that were listed. This serves as a guide if you are new to React or building an application with some complexity.

Unlike a framework such as Angular, React does not impose any architectural constraints on you. I like the flexibility this allows. However, when building a large scale, app if there isn’t any form to the application it becomes even more difficult to modify the app. These ideas aren't just for React. They can be adapted for use with any frontend library or framework.

Resources