React & Flux Tutorial: Organizing Your Redux Application

Published Jan 20, 2016Last updated Jan 18, 2017
React & Flux Tutorial: Organizing Your Redux Application

In this short piece, I want to show you an unconventional, yet surprisingly productive way to organize React/Redux (and other Flux) projects. For those who won't be able to read until the end, you can find an implementation of this approach in my React/Redux stack, Reactuate.

Many React/Redux applications adopt the following directory layout (or a variation of it):

src/
  actions/
    UserActions.js
    FooActions.js
  constants/
    UserConstants.js
    FooConstants.js
  reducers/
    UserReducers.js
    FooReducers.js
  components/
    Login.js
    Dashboard.js

Whether it is done by following other examples, or common sense, I am not sure. But I find this layout to be very counter-productive. Navigating through my applications was a nightmare (tons of imports, cross-referencing constants, etc.), all while trying to stay focused on the task at hand.

The above layout is only marginally better than organizing directories or packages by entity types. Consider doing this in Java:

com.foo.bar.
  classes
  interfaces
  singletons
  factories

Does this make a lot of sense to you? Does this tell you anything about what the application does, or how to filter out resources related to the domain you're working on? (Actually, Rails sort of made this mistake by exposing app/{models,controllers,views}

I propose organizing Redux applications by business domains. Something like this:

src/
  user/
    index.js
  orders/
    index.js
  messages/
    index.js

This way, while working on one domain, you don't need to jump across the hierarchy of a project too much, and you can easily rename the whole domain without having to rename 4-5 files!

The thought of business domains led me to another realization. What if we try to use some pieces of DDD (Domain Driven Design) to validate the data types across states and actions?

Imagine having a state defined like this:

const State = t.struct({
  currentUser: t.maybe(User)
}, 'UserState')

You can do this with tcomb!

And having an action creator defined similarly:

const doSomething = t.struct({
  type: t.refinement(t.String, (s) => s == "doSomething", "action")
  payload: t.Integer
}, "doSomething")

Now, in your reducer, you can actually use the matching capability in your reducer!

t.match(action,
  doSomething, (action) => { ... })

Notice how we got rid of the tedious constant definition/import step?

Now, there are of course some issues associated with using tcomb. For example, tcomb values are not plain objects, so Redux refuses to accept them. But this can be quite easily solved by developing a Redux middleware function.

I've recently spent some time working on a React/Redux stack that addresses this and other issues. It's called Reactuate. Most importantly, unlike other "React boilerplate" solutions, Reactuate is a library and you don't need to clone & follow it to be able to incorporate latest changes. It's still quite rough on the edges, being a few days old, but I invite you to try it out. Check it out!

Discover and read more posts from Yurii Rashkovskii
get started
Enjoy this post?

Leave a like and comment for Yurii

Be the first to share your opinion

Get curated posts in your inbox

Read more posts to become a better developer