DEV Community

Organizing Your React App Into Modules

Jack Williams on June 02, 2019

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...
Collapse
 
_pankajc profile image
Pankaj

Thanks for sharing your knowledge, Jack! This is exactly what I was looking for.

Questions:

  • How do you handle state management in your app?
  • How do you handle unit testing? Where do tests fit into this structure?
  • What were some pitfalls you encountered with this approach?

I'm currently trying to design a fairly complex SPA with React-Redux and your answers to above questions would really help me out.

Thanks!

Collapse
 
djmisterjon profile image
DjMisterJon

not big fan of REDUX
but RES are crazy for manage data, and very near of classic vanilla js structure.
All your module can be a store, and will update if they change.
github.com/RisingStack/react-easy-...

Collapse
 
jack profile image
Jack Williams

Sorry for the late reply! I thought I responded to this but I never did.

State management
Let me tell you, we went through some growing pains here. First, EVERYTHING WAS IN REDUX.

Redux all the things

Then we realized that 80% of our code could use local state, and that global state should only be used for truly global state-y things (app context, user context, etc...). We refactored redux out of most of our components where it made sense, and kept it in the few that needed it (we eventually completely removed redux, and moved to context).

Testing
It's been awhile now since I've been on that project, but if I remember correctly we used snapshot testing. Nothing real fancy here.

Pitfalls
So the other side of this "let the modules organize themselves" coin, is "where is this route, how is this rendered". Typically, all routes are in one place. You lose that with this approach.

Collapse
 
fernandosouza profile image
Fernando Souza • Edited

Hey, Jack!

Super nice article. Congrats. Succinct but well explained how decoupling should work in an application design.

The question I came up after reading was. You've exemplified how a module API exports its entry point, or the "main" component. However, a module can be built by smaller and isolated components. For instance, the Dashboard module may be an aggregation of a component exported by Games and Users module. If we agree on that, how would you suggest a Module exports its smaller components? Via the entry point API or directly from the inner component path?

Best! :)

Collapse
 
jack profile image
Jack Williams

Sorry for the delay, I took a small hiatus after writing this.

That is a good question.

On the one hand, I like to keep private sub-components of a module in the ModuleName\components folder.

But once a component becomes used in multiple places, I usually pull it up to the root components\ folder (and import from my "Components/MyComponent" alias).

Another option would be to change the signature of the modules export to have a default (which would be our contract) and named exports for internal component sharing.

Collapse
 
teetl6 profile image
teetl6 • Edited

Thanks, this helped me a lot to restructure my app in better way. Still, got warning:

src/modules/Login/index.js
  Line 31:1:  Assign object to a variable before exporting as module default  import/no-anonymous-default-export
Enter fullscreen mode Exit fullscreen mode

Because my index.js has

export default {
  routeProps: {
    path: '/login',
    component: Login
  },
  name: 'Login'
}
Enter fullscreen mode Exit fullscreen mode

What are your recommendations? Of course I can reconfigure eslint, but is there any other way to define routeProps and name?

Collapse
 
zeeglenn profile image
zeeglenn

I know almost noting about react, angular has been my ui platform for a bit, but I was able to remove that lint warning like so:

const Forms = () => (

Forms Module

);

const FormsModule =
{
routeProps: {
path: '/forms',
component: Forms
},
name: 'Forms',
};

export default FormsModule;

and the modules/index:

const Modules = {
name: 'modules',
list: [
FormsModule,
]
}
export default Modules;

and finally referencing in app like so:

Modules.list

Collapse
 
rustaceanx profile image
rustaceanX

Just edit and format your res for easy follow. Nothing special!

I know almost noting about react, angular has been my ui platform for a bit, but I was able to remove that lint warning like so:

const Forms = () => (
    FormsModule
);

const FormsModule = {
    routeProps: {
        path: '/forms',
        component: Forms
    },
    name: 'Forms',
};

export default FormsModule;
Enter fullscreen mode Exit fullscreen mode

and the modules/index:

const Modules = {
    name: 'modules',
    list: [
        FormsModule,
    ]
}

export default Modules;
Enter fullscreen mode Exit fullscreen mode

and finally referencing in app like so:

Modules.list

Collapse
 
snmpboy profile image
Mitch Raful

Wow, can't believe I just stumbled on to this. Thanks, thanks a lot... do you know how long it will take me to redo the front end piece to my app???? Seriously, it's brilliant. Like Django's individual apps in one project.

Collapse
 
aimadghssisse profile image
Aimad Ghssisse

i Like your app and i was looking for example Modules architect on react js , with redux and api ...
i know that vue js provide that and easy, by using require-context .
can i get any project example for modules architect on react js on github ? because i like to learn morre .
and also i like to ask about is that possible to make component for example _Errror.js Component , i can use it any where without call it by using import Erreur from .... ? is that possible on react js

Collapse
 
jack profile image
Jack Williams • Edited

I'm not aware of anything specifically on the react js github repo about modularizing your react components, but I've linked my example repo in the post. Hope it helps!

Collapse
 
honlordbyronmartinez profile image
Byron Martinez • Edited

You are king my friend.

It took me 4 hours to find this ......but lordy am i happy.

Question: I see alot of people doing routes on the backend with Express, are you saying that is not necessary with this method?

Thank you!

Collapse
 
jack profile image
Jack Williams • Edited

Thanks!

It isn't with this method. This method assumes full SPA with routing handled on the front-end.

The backend of my example app is actually ASP.NET Core. Some different things may have to happen with some kind of express or .net core server-side rendering / handling of routes.

Collapse
 
zackheisnberg profile image
zackheisnberg

So i learnt everything from reactjs.org/docs , and yet i was strugling to start a new project , what i truely needed that isn't in the docs is your Great amazing lovely Tut , thank you so much :) i suggest you propose it in react doc github

Collapse
 
jack profile image
Jack Williams

Thank you for the kind words!

Collapse
 
leplerjacob profile image
Jacob Lepler • Edited

This is cool. Love learning about new ways to organize a file structure. Right now working on a personal project called WaitLess using class based components. We don't use index.js, but rather .module.js | .style.css | etc...

I was wondering how to incorporate private components only used by one module. Based off your comment @jackjwilliams, I will use another folder called components inside the module folder, and stuff them into there :)

Thank you,
Jacob L
@leplerjacob <<

...btw have you heard of the "Fractal" file structure. I've used that as well

Collapse
 
webpest profile image
Abayomi Oloyinde

Hi @jack , how can one code-split the routing using this modular method, thanks in advance

Collapse
 
jack profile image
Jack Williams

Good question!

We used github.com/jamiebuilds/react-loadable for code-splitting.

Here is an example of the Dashboard modules index.jsx:

import React from 'react';
import Loadable from 'react-loadable';
import DashboardIcon from 'Components/shared/Icons/DashboardIcon';
import ScreenLoader from 'Components/shared/ScreenLoader';

const Dashboard = Loadable({
  loader: () => import('./Dashboard'),
  loading: ScreenLoader
});

export default {
  key: 'dashboard',
  routeProps: {
    path: '/dashboard',
    component: Dashboard
  },
  navigation: {
    permission: [],
    icon: (active, theme) => (
      <DashboardIcon
        style={{
          color: active ? theme.palette.dashboard[400] : theme.palette.contrast.low,
          width: 26,
          height: 26
        }}
      />
    ),
    label: 'Dashboard',
    link: '/dashboard',
    theme: 'dashboard',
  }
};
Collapse
 
sylvainlg profile image
Sylvain

Hi Jack,

Thanks for the paper.

I do you do to manage store subscription (in my case, i use redux), action sharing, reusing behaviors between modules and all those React things ?

Collapse
 
jack profile image
Jack Williams

Sorry for the delay, I took a small hiatus after writing this.

Originally, in our app, we used plain old redux. It was a mess.

Then, on every screen, we asked ourselves:

Does this REALLY NEED to be in redux for global state?

The answer, 95% of the time, was no. We refactored out redux and went with Context for truly global state (App state, user state, etc...).

But, to answer your question in 2020 of how I would do it (managing actions / reducers):

For actions / reducers
Use Redux Toolkit or something similar (redux-toolkit.js.org/). Creating all those actions and reducers and managing them was a nightmare.

For shared behavior
Hooks are exactly what that was made for. Got a bug service? useBugs() might return { createBug, searchBugs }. Import and use anywhere.

Collapse
 
webpest profile image
Abayomi Oloyinde

You deserve an accolade

Collapse
 
pbsonawane profile image
Pravin

How we can manage session or user authorization for this multiple modules****

Collapse
 
raminhbbau profile image
RaminHbb

That's a good idea .... Thanks for sharing