22

I would like to know what are the pros and cons of using a Fractal Structure in a React + Redux project and I was wondering if anyone has any experience with this approach or if there are pitfalls which are not immediately visible from the docs.

(Fractal structure) Also known as: Self-Contained Apps, Recursive Route Hierarchy, Providers, etc

Context: I'm looking at react-redux-starter-kit and it suggests to use a fractal structure to organize the folders. If I understood well, this approach require to organize the project folders by feature and nest the route recursively.

So, if I have a "events" resources where

  • /events lists all the events
  • /events/new show a form to insert a new event
  • /events/1/details show the details about the event with id 1

Starting from the boilerplate, I have to add the new route folder like:

├── src                      # Application source code
│   ├── main.js              # Application bootstrap and rendering
│   ├── components           # Reusable Presentational Components
│   ├── containers           # Reusable Container Components
│   ├── layouts              # Components that dictate major page structure
│   ├── static               # Static assets (not imported anywhere in source code)
│   ├── styles               # Application-wide styles (generally settings)
│   ├── store                # Redux-specific pieces
│   └── routes               # Main route definitions and async split points
│       ├── index.js         # Bootstrap main application routes with store
│       ├── Root.js          # Wrapper component for context-aware providers
~       ~
│       ├── Events           # Fractal route
│       │   ├── index.js     # Route definitions and async split points
│       │   ├── components   # Presentational React Components
│       │   ├── container    # Connect components to actions and store
│       │   ├── modules      # Collections of reducers/constants/actions or single DUCK module
│       │   └── routes       # Fractal sub-routes (** optional) <-------------
│       │       │
│       │       └── New
│       │       │   ├── index.js     # Route definitions and async split points
│       │       │   ├── assets       # Assets required to render components
│       │       │   ├── components   # Presentational React Components
│       │       │   ├── container    # Connect components to actions and store
│       │       │   ├── modules      # Collections of reducers/constants/actions or single DUCK module
│       │       │   └── routes       # Fractal sub-routes (** optional) <-------------
│       │       │
│       │       └── Details
│       │           ├── index.js     # Route definitions and async split points
│       │           ├── assets       # Assets required to render components
│       │           ├── components   # Presentational React Components
│       │           ├── container    # Connect components to actions and store
│       │           ├── modules      # Collections of reducers/constants/actions or single DUCK module
│       │           └── routes       # Fractal sub-routes (** optional) <-------------
~       ~
│       └── NotFound         # Capture unknown routes in component
~

With New and Details folder nested under the root Event folder.

The docs highlight this main pros:

  • It scales better than a flat directory structure, with folders for components, containers, etc.
  • Routes can be be bundled into "chunks" using webpack's code splitting and merging algorithm
  • Since logic is self-contained, routes can easily be broken into separate repositories and referenced with webpack's DLL plugin for flexible, high-performance development and scalability.
NickGnd
  • 5,107
  • 1
  • 20
  • 26

2 Answers2

7

The one drawback or con I've encountered with a similar structure is if/when things starts being used outside of it's hierarchy, then you have to use a lot of ../../.. in your imports.

For example, say that you get the requirement that on your StartPage route you should show the details for the most recent event.

so now it looks like:

routes
├─Events
│     ├─New
│     ├─Details
├─StartPage
       ├─ components   // here somewhere you import ../../Events/Details

It's not the end of the world, but your nice hierarchy isn't quite as strictly hierarchical anymore.

Markus-ipse
  • 7,196
  • 4
  • 29
  • 34
  • 12
    Thanks for your answer. You can use the webpack `resolve.root` config to avoid `../../..` for every import. See [docs](https://webpack.github.io/docs/configuration.html#resolve-root) or [this](http://stackoverflow.com/questions/27502608/resolving-require-paths-with-webpack) question on SO – NickGnd Jul 11 '16 at 12:42
  • There's also 'babel-plugin-module-resolver', if you want it to work in the backend as well. – Stefan Fisk Nov 12 '16 at 13:06
  • 1
    When using `resolve.root` or the module-resolver plugin for babel I think you'll loose a lot of the benefits that your editor (or other code analyzing tools) can provide, e.g. being able to directly jump to the definition/declaration of a function that is imported from another file. – Markus-ipse Dec 29 '16 at 11:03
  • 1
    @Markus-ipse I would challenge your structure to say maybe you should have a higher component class that sits outside both the Events and StartPage routes directories, and they both use that same component. This is, after all, one of the main points of React: reusable components. My thinking for the correct structure is if multiple routes use the same component, then move it out to a higher level component directory. Only components specific to its route should reside within a route's directory hierarchy. – jflay Apr 26 '17 at 17:46
  • Nowadays IDE tooling auto-formats import statements. I never have to worry about `../../../` anymore. (I'm in VS Code). – trusktr Sep 25 '20 at 23:04
1

The one drawback that I can speak to is not being able to at a glance view all available routes and their respective components, this can be mitigated by making some descriptive comments, but it does increase the complexity of your route configuration. I would also try to keep nesting folders to minimum since there is cognitive load associated with getting the levels of nesting right in your import statements i.e ../../../../../ these can get out of hand if you have many nested routes.

deowk
  • 4,280
  • 1
  • 25
  • 34
  • 3
    You can use webpack or babel plugin for aliasing modules. Have an alias for your top-level app directory and always import from there. – moljac024 Jul 07 '16 at 18:50