Libraries and architecture

We use the following libraries and projects to build our UIs:

Framework

  • React: UI library
  • Redux: state management and flux framework
  • Normalizr: for data normalization
  • Reselect: for passing data to components

Framework extensions:

Tooling:

  • webpack: module bundler
  • postcss: css preprocess manager
  • cssnext: css transpiling using future css syntax

This list isn't exhaustive though it comprises the most important tools in our stack. Each library solves a particular problem with frontend development; we'll walk through each of them in the coming chapter.

Architecture

Redux follows the general flux architecture. All state is stored globally and is modified via actions. The flow of data and logic looks like this:

  1. Starting at the bottom right we have components that can trigger actions.
  2. Actions are flux' way of requesting that a state mutation happens. Each action may have a side effect like an API request
  3. The action passes through middleware. Middleware handle action-specific tasks like listening to promise statuses. Middleware can also trigger new actions.
  4. Once actions flow through the middleware they're passed into reducers
  5. Reducers receive the action and any associated data. Reducers can choose to change global state within the store by returning new state.
  6. Any state changes propagate to reselect selectors. The selectors transform data and pass it to components
  7. Components receive the state they need as props, and render HTML to the DOM.

It's important to understand this flow, and it's even more important to know why we stick to it.

Architecture benefits

This architecture has several benefits over classical frameworks such as Ember or Angular.

Implementing redux as 'flux' framework means that all data flows in a single direction. Having this means:

  1. There are no side effects in components; components are predictable and understandable
  2. Components can't directly modify state, so there's no need for data binding or event systems
  3. It's hard to fall out of sync and mismanage state as all state is managed globally
  4. Middleware can handle complex side effects such as listening to promise statuses

We've added reselect as an intermediary between the redux store and components; classically components get state directly from the store. Reselect queries and transforms data for each component. This means that each component is entirely reusable because they only display data they're given. We talk about this more in the 'transforming state per component' chapter.

Future architecture plans

Fetching and normalizing data from each component using actions works, though it isn't declarative.

Ideally components would declare data they need without worrying about fetching data. We'd then have some background logic that takes care of API requests, caching, and data transformation on the component's behalf.

This is the idea behind Falcor and Relay. These mean that each component can be completely declarative, making things even easier to build and understand.