Hard and fast rules for Redux apps

We've had more than our fair share of messy code and mishaps. While working through these we've learned some general rules to follow when you're building react apps. Follow these and your life will include less profanity than ours (while building your UI at least).

State management

  1. Use Falcor or normalizr + reselect to normalize state shape in reducers
  2. Store each resource:
    1. using immutable.js
    2. in its own reducer
    3. store the entire normalizr result, not just entities
    4. think about storing data within maps of parent resources (ie. for github, store repositories keyed by user/org names: { 'docker': data } vs storing just normalized data)
  3. Middleware that records state should have their own reducers
  4. UI state should be managed globally via something like redux-ui
  5. Use Immutable records where possible

Writing code

  1. Use ES7
  2. Most actual code should be written as:
    1. Redux middleware
    2. Reselect selectors (for querying and transforming state/resources)
    3. Higher-order-components - usually as decorators
  3. This means you should almost never write logic in a plain UI component

UI components

  1. Should always (try and) be dumb (ie. have no state)
    1. If components need state it should be global but ephemeral (see redux-ui)
  2. Should specify their props in propTypes (eslint enforced)
  3. Should have their own CSS files included via postcss + react-css-modules + style-loader
  4. Should always load data declaratively if possible
  5. Should never transform data itself; to transform data use reselect

Higher order components

  1. Should always use ES7 decorators for application
  2. May maintain internal state depending on complexity and needs
  3. By nature may contain business logic

Selectors

  1. Separate selectors into files (users, posts, router etc)
  2. Use a router selector for query state and params from the router: this will be used in other selectors and will become a dependency
  3. Prefix selectors with get: getCurrentUser for the logged in user, getRouteUser for the user from the current router param etc.

Misc: forms, other redux components

  1. Use redux-form.

Code structure

actions/
components/
  hoc/
  elements/
middleware/
reducers/
scenes/
selectors/
utils/
*.js

Example:

actions/
  index.js
  posts.js
  ui.js
components/
  hoc/
    modal/
      modal.js
      modal.css
  elements/
    button/
      button.js
      button.css
middleware/
  promise.js
reducers/
  posts.js
  promise.js <- from middleware/promise.js for tracking statuses
  ui.js      <- stores all UI state for each component
scenes/
  dashboard/
    index.js
    dashboard.js
    dashboard.css
    selectors.js <- component-specific selectors
  posts/
    index.js
    posts.js
    posts.css
  post/
    index.js
    post.js
    post.css
selectors/
  posts.js     <- general selectors (if desired)
utils/
  index.js
container.css
container.js
consts.js      <- consts used throughout the app
index.js       <- loads ReactDOM and injects routes
normalizers.js <- Normalizr configruation
records.js     <- Immutable.js record definitions
routes.js