Flux

What is Flux

Flux is an architecture for handling data.

 

​Characteristics:

  • explicit and understandable update paths
  • maintains a strict decoupling of components
  • makes tracing changes during development simpler
  • bugs are easier to track down and fix

The big picture

MVC pattern

Flux pattern

Problems with MVC

When more than one Controller modifies a Model:

  • the dependency graph becomes harder to trace
  • it's hard to debug when the models have dependencies

Flux architecture

Main components:

  • views
    • are responsible for handling an action by a user
    • send requests for data to the stores via the dispacher
  • dispatcher 
    • takes requests for actions from the views 
    • pass the requests to the pertinent store (or stores)
  • stores – store state
    • wake up on a relevant dispatch to retrieve the requested data
    • notify the views of changes
  • actions – provide actions for the views

Problems with Flux

  • no official architecture implementation
    • Facebook only provides the dispacher
  • lots of small competing implementations
  • no clear unified way on how to deal with async actions
  • no clear way of how to resolve dependency between stores
    • dispatcher contains waitFor method

Flummox

Provides a clean implementation, that is ES6 compatible.

  • doesn't rely on mixins
  • doesn't use higher order components structure
  • based on extending 3 classes Action, Store and Flux

 

Components:

  • Action class

Actions

  • we created a single action, createMessage
  • the return value is sent through the dispatcher automatically

 

Async handling:

  • if you return a Promise, Flummox will wait for the Promise to resolve and then dispatch the unwrapped value
  • can also use the ES7 async-wait pattern

import { Actions } from 'flummox';

class MessageActions extends Actions {
  createMessage(messageContent) {
    return {
      content: messageContent,
      date: Date.now(),
    };
  }
}

Stores

import { Store } from 'flummox';

class MessageStore extends Store {
  constructor(flux) {
    super(); // Don't forget this step

    const messageActionIds = flux.getActionIds('messages');
    this.register(messageActionIds.createMessage, this.handleNewMessage);

    this.state = {
      messages: [],
    };
  }

  handleNewMessage(message) {
    this.setState({
      messages: this.state.messages.concat([message]),
    });
  }
}
  • set initial state by assigning to this.state in the constructor
  • update state by using this.setState()
  • a change event is emitted automatically whenever you call this.setState()
  • emit events manually using this.emit()

Flux Class

 

import { Flux } from 'flummox';

class AppFlux extends Flux {
  constructor() {
    super();

    this.createActions('messages', MessageActions);

    // The extra argument(s) are passed to the MessageStore constructor
    this.createStore('messages', MessageStore, this);
  }
}
  • unifies our stores and actions, along with a dispatcher, into a single, self-contained instance.
  • registers the Actions and the Stores
  • each instance has its own dispatcher

Use it in a view

import FluxComponent from 'flummox/component';

class MessagesView extends React.Component {
  render() {
    return (
      <FluxComponent connectToStores={{
        messages: store => ({
          messages: store.messages
        })
      }}>

        // MessageList is injected with a `messages` prop by FluxContainer
        <MessageList />
      </FluxComponent>
    );
  }
}
<FluxComponent flux={flux}>
  // Immediate children have flux prop
</FluxComponent>
<FluxComponent>
  // Same as last time: immediate children have flux prop
  // flux is already part of context, and remains so
</FluxComponent>

FluxComponent

FluxComponent:

  • it uses the React context to expose the Flux instance to nested views
  • makes it easy to subscribe to store updates
  • the immediate children get the stores as properties
    • so you don't have to explicitly pass properties down the component tree
  • pass a flux instance as a prop to a FluxComponent near the top of your app hierarchy, any FluxComponents further down the tree will automatically have access to it

Access flux from context

class MyComponent extends React.Component {
    constructor (props, context) {
        super(props, context);
    }
}

MyComponent.contextTypes = {
  flux: React.PropTypes.object.isRequired
};
<FluxComponent flux={flux}>
    <App>
        <MyComonent/>
    </App>
</FluxComponent>
  • pass the context as the second param of the constructor
  • define flux in the contextTypes of the React component

Final thoughts

  • the maintainer of Flummox recommends using Redux instead
  • Redux is less popular than Flummox 271 vs 1255 downloads 
  • we should consider it if
    • plays nice with ES6 classes
    • no mixins, no higher order components

Flux

By kenjiru

Flux

Flux & Flummox overview

  • 671