Flux

"React Goes Big"

React: Declarative Render

var NumberSelector = React.createClass({
  render: function() {
    return (
      <div>
        <p>You selected: Nothing</p>
        <select>
          <option>1</option>
          <option>2</option>
          <option>3</option>
        </select>
      </div>
    )
  },
})

React: Component State

var NumberSelector = React.createClass({
  getInitialState: function() {
    return {
      selectedValue: 1 
    }
  },
  render: function() {
    return (
      <div>
        <p>You selected: {this.state.selectedValue}</p>
        <select value={this.state.selectedValue}>
          <option>1</option>
          <option>2</option>
          <option>3</option>
        </select>
      </div>
    )
  },
})

React: Modifying State

var NumberSelector = React.createClass({
  getInitialState: function() {
    return {
      selectedValue: 1
    }
  },
  render: function() {
    return (
      <div>
        <p>You selected: {this.state.selectedValue}</p>
        <select
          value={this.state.selectedValue}
          onChange={this.handleChange}
        >
          <option>1</option>
          <option>2</option>
          <option>3</option>
        </select>
      </div>
    )
  },
  handleChange: function(ev) {
    this.setState({
      selectedValue: ev.target.value
    })
  }
})

React Recap

  • State lives in one place
  • Rendered view derived from state
  • Explicit actions modify state

One-way data flow inside a component

Flux: React Goes Big

State

DOM 

Tree

Events

Stores

View 

(React.js)

Actions

Actions

View 

(React)

Flux: Stores

var SelectedValueStore = {























}
  /* storage */
  _value: 1,

  getValue: function() {
    return this._value 
  },
  /* event emitter */
  
  _handlers: [],

  addChangeHandler: function(func) {
    this._handlers.push(func)
  },

  removeChangeHandler: function(func) {
    var idx = this._handlers.indexOf(func)
    this._handlers.splice(idx, 1)
  },

  emitChange: function() {
    this._handlers.forEach(function(func){ func() })
  },
  • Expose data
       via getter functions
     
  • Notify subscribers
      of changes 
     
  • DON'T expose setters
     
  • DON'T fetch data

Flux: Stores

var NumberSelector = React.createClass({

























})
  • Read app state
     
  • Subscribe to
      changes
  /* subscribe to change events (and unsubscribe): */
  componentWillMount: function() {
    SelectedValueStore.addChangeHandler(this._handleValueChanged)
  },
  componentWillUnmount: function() {
    SelectedValueStore.removeChangeHandler(this._handleValueChanged)
  },
  /* read state from store: */
  getInitialState: function() {
    return {
      selectedValue: SelectedValueStore.getValue()
    }
  },
  render: function() {
   /* render stays the same :D */
  },
  /* handle change events by re-reading from store: */
  _handleValueChanged: function() {
    this.setState({
      selectedValue: SelectedValueStore.getValue()
    })
  },

Flux: Actions

/* this is Facebook's dispatcher */
var valueDispatcher = new Flux.Dispatcher()




var ValueSelectionActions = {

  /* this function creates a VALUE_WAS_SELECTED action: */
  valueWasSelected: function(value) {







  },
}
  • Broadcasted by a dispatcher 

 

  • POJO with  `actionType`, at least
    var action = {
      actionType: "VALUE_WAS_SELECTED",
      value: value,
    }
    valueDispatcher.dispatch(action)

Flux: Actions

/* make a handler */
var SelectedValueStore = {
  // ...
  _actionHandler: function(payload) {
    if (payload.actionType == "VALUE_WAS_SELECTED") {
      this._value = payload.value    // update state 
      this.emitChange()              // broadcast changes
    } 
  },
}

  • Stores handle actions 

     
  • Callbacks are registered on the dispatcher
/* hook up the store */
var boundCallback = SelectedValueStore._eventHandler.bind(SelectedValueStore)
valueDispatcher.register(boundCallback)

Flux: Actions

/* trigger the action from the view: */

var NumberSelector = React.createClass({
  // ...
  handleChange: function(ev) {



  },
})

Views trigger application actions in response to user input 

    // don't set local state, 
    // instead, trigger event for the whole application
    ValueSelectionActions.valueWasSelected(ev.target.value)

Flux

Flux Implementations

  • Facebook's dispatcher (facebook/flux)
  • Facebook's event emitter (facebook/emitter)
     
  • McFly (kenwheeler/mcfly)
     
  • Flummox (acdlite/flummox, ES6-friendly)

Flux Lab

Your Questions?

Robert Mosolgo 

Full Stack, March 12, 2015

Flux

By Robert Mosolgo

Flux

Flux from the angle of: "Flux is React's one-way data flow, but bigger"

  • 1,444