React: initial project setup, structure and architecture

Starting with React is quite easy. You just need to install the npm package and can create your components. However, unlike Angular, React is not providing a whole ecosystem which comes with a architecture and everything necessary like router, module system, components, templates already prepared for immediate start. Angular is a framework, whereas React is a library for creating ui interfaces! This is a huge difference (framework vs. library). In this short article I show an example architecture which you can use, if you don’t know how to structure your app.

Project setup

npm install -g create-react-app
create-react-app demo-app
cd demo-app

That’s it! “create-react-app” also creates npm command for start (development server), build (for production deployment) and test (for jest). This is already a huge step forward, so that you don’t need to do this manually. The forth created command is eject. Don’t use this! Better delete it. Exception: you know exactly what you do. This command will “eject” the automatically created build/test commands and leave you with the configuration. You should only do this, if you are very comfortable with these things.

Project structure and architecture

It is best practice to separate your app into modules 😉 Using modules you define public interfaces and hide unnecessary details to the user of the modules which is a huge benefit when developing big software systems. In React you can easily create your own modules: ES6 modules. Use them!

The file structure could look as follows:

src/
    dashboard/
        components/ --> the actual React components
        containers/ --> often also called "pages", parent of components
        reducers/ --> if you are using Redux for state management
        actions/ --> if you are using Redux for state management
        index.js --> PUBLIC interface of this module!
   module2/
        ... --> same structure
   ui/
        ... --> an own module for app wide ui!
   App.jsx

Some hints for the structure:

  • create for each module an own directory
  • group your source code by “type” like components, containers, …
  • export in index.js only the public interface of this module – often only some container or components!
  • DON’T use a module “shared” – this is most often just an indicator for badly cut modules (if cut at all). It tends to become huge and the overview is lost. Also the dependencies between the modules are not visible if every module is depending on a big huge “shared” module containing actually almost everything. It is better to implement the feature in an own module and then export the functionality in the index.js file for the module.
  • DON’T have a huge App.jsx – in your main application component only the most essential stuff should happen which is on an application level. This means general configuration and module setup. The App.jsx should only contain the bootstrapping. Work is done in own components and not here!

An example for an App.jsx using the React contexts is shown below:

// imports ...

export default function App() {
  return (
    <KeycloakSsoProvider>
      <ThemeProvider>
        <TranslationProvider>
          <Router>
            ....
          </Router>
        </TranslationProvider>
      </ThemeProvider>
    </KeycloakSsoProvider>
  )
}

This App component only contains the most important application wide contexts. Like SSO (in this example the user must be authenticated to use the application), Theme, i18n and latest router.

Yes, use a router for your app. Even it is small one. Why? It allows you loose coupling and make so much things easier. But there will an own article about router at some point of time.

Another word on contexts: use them. But right. Don’t use them to pollute your application with data which are only for two-three components. Only use contexts for topics which are applied on the whole application. Like the mentioned one above.