Upgrade to Pro — share decks privately, control downloads, hide ads and more …

react-flux-fluent-2015-notes

 react-flux-fluent-2015-notes

Bill Fisher

April 21, 2015
Tweet

More Decks by Bill Fisher

Other Decks in Technology

Transcript

  1. React + Flux
    Two Great Tastes that Taste Great Together
    Bill Fisher @fisherwebdev #ReactJS

    View Slide

  2. https://speakerdeck.com/fisherwebdev/react-flux-fluent-2015
    bit.ly/1Hrqfpc

    View Slide

  3. React
    https://speakerdeck.com/fisherwebdev/react-flux-fluent-2015
    Flux
    +
    React is a framework for building UI, for the view layer. Flux is a pattern, not a framework, for managing application state.
    !
    There’s a lot of excitement about React these days. Lots of people are using React and Flux - Khan Academy, Yahoo, Airbnb, Soundcloud, and many others.
    !
    React and Flux were created separately, but they compliment each other as each is based on similar ideas:
    a unidirectional data flow
    continuous change
    declarative code over imperative code
    simplicity
    !

    View Slide

  4. https://speakerdeck.com/fisherwebdev/react-flux-fluent-2015

    View Slide

  5. https://speakerdeck.com/fisherwebdev/react-flux-fluent-2015
    A story…

    View Slide

  6. Model
    Model
    Model
    Model
    The perfect application, with no derived state.

    View Slide

  7. Model
    Model
    Model
    Model
    Eventually, we need a feature that requires derived state.
    We need to know the state of one model within another model, so that model will know if or how it should update itself.

    View Slide

  8. Model
    Model
    Model
    Model
    The model with derived state is now a second class citizen in the app.

    View Slide

  9. Model
    Model
    Model
    Model
    Usually, these data dependencies are needed by many models.

    View Slide

  10. Model
    Model
    Model
    Model
    Additional features will create new dependency trees. Now we have a weave of dependencies that we need to maintain, reason about, and be able to
    explain to new members of our team.

    View Slide

  11. And the application grows.

    View Slide

  12. And grows some more.

    View Slide

  13. And eventually, we might have no single source of truth in the application as our application state has become a tangled weave of data dependencies. It’s
    very difficult to reason about an application like this. As changes cascade through the data layer, our application state becomes highly unstable.

    View Slide

  14. "Tangled wires, Freegeek, Portland, Oregon, USA" by Cory Doctorow, used under CC BY 2.0\
    What we have is complete mess.
    !

    View Slide

  15. "Spaghetti? Yum!" by Dan McKay, used under CC BY 2.0
    It’s a form of spaghetti code.
    !
    Many people deal with this with an evented, publish-subscribe approach, but this just turns our spaghetti code into invisible spaghetti code, making it even more unstable as we have no
    control over the order in which the events will propagate changes through the application.
    !
    So at Facebook, we took a look at this problem, and instead of going down a traditional MVC path, we created Flux.

    View Slide

  16. Dispatcher
    Action
    Store
    View
    This is Flux:
    - avoid spaghetti code
    - grow apps with confidence
    - bring on new people quickly
    - mental models matter!
    Four major parts: action, dispatcher, store, views (React)

    View Slide

  17. js  
    ├──  
    │  
    ├──  AppBootstrap.js  
    ├──  AppConstants.js  
    ├──  
    ├──  
    │  
    │  
    │  
    ├──  utils  
    │      ├──  AppWebAPIUtils.js  
    │      ├──  FooUtils.js  
    │      └──  __tests__  
    │              ├──  AppWebAPIUtils-­‐test.js  
    │              └──  FooUtils-­‐test.js  
    └──    
    !
    actions  
    └──  MessageActionCreators.js
    AppDispatcher.js
    stores  
    ├──  MessageStore.js  
    └──  __tests__  
           └──  MessageStore-­‐test.js
    views  
    ├──  MessageControllerView.react.js  
    └──  MessageListItem.react.js
    Dispatcher
    Action
    Store
    View

    View Slide

  18. js  
    ├──  
    │  
    ├──  AppBootstrap.js  
    ├──  AppConstants.js  
    ├──  
    ├──  
    │  
    │  
    │  
    ├──  utils  
    │      ├──  AppWebAPIUtils.js  
    │      ├──  FooUtils.js  
    │      └──  __tests__  
    │              ├──  AppWebAPIUtils-­‐test.js  
    │              └──  FooUtils-­‐test.js  
    └──    
    !
    actions  
    └──  MessageActionCreators.js
    AppDispatcher.js
    stores  
    ├──  MessageStore.js  
    └──  __tests__  
           └──  MessageStore-­‐test.js
    views  
    ├──  MessageControllerView.react.js  
    └──  MessageListItem.react.js
    Dispatcher
    Action
    Store
    View

    View Slide

  19. actions  
    └──  MessageActionCreators.js
    Action
    Actions & Action Creators

    View Slide

  20. Actions & Action Creators
    Actions:
    an object with a type property and new data, like events
    Action creators:
    semantic methods that create actions
    collected together in a module to become an API
    Actions are a lot like events, in that they have a type and they carry some data along with them.
    !
    Actions creators are just methods that hand actions to the dispatcher.
    !
    We collect them together to make them easy to find at a later time, and this library becomes the API.

    View Slide

  21. "A copy of the San Francisco Chronicle from when the Apollo 11 mission made it to the moon." by zpeckler, used under CC BY 2.0
    Actions should be like newspapers, reporting some something that has happened in the world. For example, the user clicked, the server responded, or
    the browser completed an animation frame.

    View Slide

  22. //  MessageActionCreators.js  
    !
    var  AppDispatcher  =  require('../AppDispatcher');  
    var  AppConstants  =  require('../AppConstants');  
    !
    var  ActionTypes  =  Constants.ActionTypes;  
    !
    module.exports  =  {  
    !
       
    !
    !
    !
    !
    !
    !
    };
    messageCreated:  text  =>  {  
       AppDispatcher.dispatch({  
           type:  ActionTypes.MESSAGE_CREATED,  
           text  
       });  
    },
    Here’s what they look like inside the action creators module. Let’s focus on a single action creator.

    View Slide

  23. messageCreated:  text  =>  {  
       AppDispatcher.dispatch({  
           type:  ActionTypes.MESSAGE_CREATED,  
           text  
       });  
    },

    View Slide

  24.    messageCreated:  text  =>  {  
           AppDispatcher.dispatch({  
               type:  ActionTypes.MESSAGE_CREATED,  
               text  
           });  
       }
    Here we can see the action itself in yellow. The action creator is simply handing that yellow action object to the dispatcher.
    !
    Note that I’m using the past tense to name both the method and the type.
    !
    I could have named this “createMessage” but instead I’ve named it “messageCreated”.
    !
    I’m doing that to keep myself focused on the idea that this is a report on something that has already happened, not an imperative command involving implementation details.
    !

    View Slide

  25. js  
    ├──  
    │  
    ├──  AppBootstrap.js  
    ├──  AppConstants.js  
    ├──  
    ├──  
    │  
    │  
    │  
    ├──  utils  
    │      ├──  AppWebAPIUtils.js  
    │      ├──  FooUtils.js  
    │      └──  __tests__  
    │              ├──  AppWebAPIUtils-­‐test.js  
    │              └──  FooUtils-­‐test.js  
    └──    
    !
    actions  
    └──  MessageActionCreators.js
    AppDispatcher.js
    stores  
    ├──  MessageStore.js  
    └──  __tests__  
           └──  MessageStore-­‐test.js
    views  
    ├──  MessageControllerView.react.js  
    └──  MessageListItem.react.js
    Dispatcher
    Action
    Store
    View

    View Slide

  26. js  
    ├──  
    │  
    ├──  AppBootstrap.js  
    ├──  AppConstants.js  
    ├──  
    ├──  
    │  
    │  
    │  
    ├──  utils  
    │      ├──  AppWebAPIUtils.js  
    │      ├──  FooUtils.js  
    │      └──  __tests__  
    │              ├──  AppWebAPIUtils-­‐test.js  
    │              └──  FooUtils-­‐test.js  
    └──    
    !
    AppDispatcher.js
    Dispatcher
    Action
    Store
    View
    stores  
    ├──  MessageStore.js  
    └──  __tests__  
           └──  MessageStore-­‐test.js
    views  
    ├──  MessageControllerView.react.js  
    └──  MessageListItem.react.js
    actions  
    └──  MessageActionCreators.js

    View Slide

  27. AppDispatcher.js
    Dispatcher
    The Dispatcher

    View Slide

  28. The Dispatcher
    "Sunset at Sutro" by ohad*, used under CC BY 2.0
    The dispatcher is like a radio tower, indiscriminately broadcasting the action to all of the stores.

    View Slide

  29. Dispatcher
    Action
    Store
    View
    It’s also like the the center of a dipole. All data flows through the dispatcher.
    !
    Diagrams like this, showing magnetic flux, were the mental image in Jing Chen’s mind when she named Flux.

    View Slide

  30. Available through npm or Bower as flux
    A singleton registry of callbacks, similar to EventEmitter
    dispatch(action): invokes all callbacks, provides action
    Primary API: dispatch(), register(), waitFor()
    The Dispatcher

    View Slide

  31. waitFor() is a distinctive feature, vital for derived state
    Cannot dispatch within a dispatch
    Each dispatch is a discrete moment of change
    The Dispatcher

    View Slide

  32. //  AppDispatcher.js  
    !
    var  Dispatcher  =  require('Flux.Dispatcher');  
    !
    //  export  singleton  
    module.exports  =  new  Dispatcher();

    View Slide

  33. js  
    ├──  
    │  
    ├──  AppBootstrap.js  
    ├──  AppConstants.js  
    ├──  
    ├──  
    │  
    │  
    │  
    ├──  utils  
    │      ├──  AppWebAPIUtils.js  
    │      ├──  FooUtils.js  
    │      └──  __tests__  
    │              ├──  AppWebAPIUtils-­‐test.js  
    │              └──  FooUtils-­‐test.js  
    └──    
    !
    actions  
    └──  MessageActionCreators.js
    AppDispatcher.js
    stores  
    ├──  MessageStore.js  
    └──  __tests__  
           └──  MessageStore-­‐test.js
    views  
    ├──  MessageControllerView.react.js  
    └──  MessageListItem.react.js
    Dispatcher
    Action
    Store
    View

    View Slide

  34. js  
    ├──  
    │  
    ├──  AppBootstrap.js  
    ├──  AppConstants.js  
    ├──  
    ├──  
    │  
    │  
    │  
    ├──  utils  
    │      ├──  AppWebAPIUtils.js  
    │      ├──  FooUtils.js  
    │      └──  __tests__  
    │              ├──  AppWebAPIUtils-­‐test.js  
    │              └──  FooUtils-­‐test.js  
    └──    
    !
    AppDispatcher.js
    stores  
    ├──  MessageStore.js  
    └──  __tests__  
           └──  MessageStore-­‐test.js
    Dispatcher
    Action
    Store
    View
    actions  
    └──  MessageActionCreators.js
    views  
    ├──  MessageControllerView.react.js  
    └──  MessageListItem.react.js

    View Slide

  35. Stores
    Store
    stores  
    ├──  MessageStore.js  
    └──  __tests__  
           └──  MessageStore-­‐test.js

    View Slide

  36. Stores
    Courtesey of The Bancroft Library, UC Berkeley BANC PIC 1905.17500 v.10:141--ALB
    Stores are highly decoupled domain models and are the locus of control in the application.

    View Slide

  37. Stores
    Each store is a singleton
    The locus of control within the application
    Manages application state for a logical domain
    Private variables hold the application data
    Numerous collections or values can be held in a store
    That is, they manage the state for a logical domain: we might have a FriendStore, a PhotoStore or a MessageStore where a collection is managed, or we
    might have something more abstract like a TimeStore.
    !
    Collections or values may be managed - any way to manage state that makes sense.

    View Slide

  38. Stores
    Register a callback with the dispatcher
    Callback is the only way data gets into the store
    No setters, only getters: a universe unto itself
    Emits an event when state has changed
    How they work:
    1. Register a callback with dispatcher - this is the only way into the store.
    2. When state changes, they emit change to alert the view layer.
    !
    If data dependencies occur, we use waitFor()

    View Slide

  39. //  MessageStore.js  
    !
    var  _dispatchToken;  
    var  _messages  =  {};  
    !
    class  MessageStore  extends  EventEmitter  {  
    !
       constructor()  {  
           super();  
           _dispatchToken  =  AppDispatcher.register(action  =>  {  
    !
               switch(action.type)  {  
    !
                   case  ActionTypes.MESSAGE_CREATE:  
                       var  message  =  {  
                           id:  Date.now(),  
                           text:  action.text  
                       }  
                       _messages[message.id]  =  message;  
                       this.emit('change');  
                       break;  
    !
                   case  ActionTypes.MESSAGE_DELETE:  
                       delete  _messages[action.messageID];  
                       this.emit('change');  
                       break;  
    !
                   default:  
                       //  no  op  
               }  
    !
           });  
       }  
    !
       getDispatchToken()  {  
           return  _dispatchToken;  
       }  
    !
       getMessages()  {  
           return  _messages;  
       }  
    !
    }  
    !
    module.exports  =  new  MessageStore();  
           _dispatchToken  =  AppDispatcher.register(action  =>  {  
    !
               switch(action.type)  {  
    !
                   case  ActionTypes.MESSAGE_CREATED:  
                       var  message  =  {  
                           id:  Date.now(),  
                           text:  action.text  
                       }  
                       _messages[message.id]  =  message;  
                       this.emit('change');  
                       break;  
    !
                   case  ActionTypes.MESSAGE_DELETED:  
                       delete  _messages[action.messageID];  
                       this.emit('change');  
                       break;  
    !
                   default:  
                       //  no  op  
               }  
    !
           });  
    private variables at the top
    getters at the bottom
    the real action is in the registered callback

    View Slide

  40.        _dispatchToken  =  AppDispatcher.register(action  =>  {  
    !
               switch(action.type)  {  
    !
                   case  ActionTypes.MESSAGE_CREATED:  
                       var  message  =  {  
                           id:  Date.now(),  
                           text:  action.text  
                       }  
                       _messages[message.id]  =  message;  
                       this.emit('change');  
                       break;  
    !
                   case  ActionTypes.MESSAGE_DELETED:  
                       delete  _messages[action.messageID];  
                       this.emit('change');  
                       break;  
    !
                   default:  
                       //  no  op  
               }  
    !
           });  
    respond to action types, or do nothing if this store is not interested
    emit change after modifying private variables that hold application state

    View Slide

  41. Testing Stores with Jest
    Stores have no setters — how to test is not obvious
    Jest is Facebook’s auto-mocking test framework
    Built on top of Jasmine
    http://facebook.github.io/jest/
    http://facebook.github.io/flux/docs/testing-flux-
    applications.html

    View Slide

  42. callback  =  AppDispatcher.register.mock.calls[0][0];  
    Give me a reference to the first argument of the first call to AppDispatcher's register() method.

    View Slide

  43. jest.dontMock('MessageStore');  
    !
    var  AppConstants  =  require('AppConstants');  
    !
    var  ActionTypes  =  AppConstants.ActionTypes;  
    !
    describe('MessageStore',  function()  {  
    !
       var  callback;  
    !
       beforeEach(function()  {  
           AppDispatcher  =  require('AppDispatcher');  
           MessageStore  =  require('MessageStore');  
           callback  =  AppDispatcher.register.mock.calls[0][0];  
       });  
    !
       it('can  create  messages',  function()  {  
           callback({  
               type:  ActionTypes.MESSAGE_CREATED,  
               text:  'test'  
           });  
           var  messages  =  MessageStore.getMessages();  
           var  firstKey  =  Objects.keys(messages)[0];  
           expect(MessageStore.getMessages()[firstKey].text).toBe('test');  
       });  
    !
    });  
    callback  =  AppDispatcher.register.mock.calls[0][0];  

    View Slide

  44. Dispatcher
    Action
    Store
    View
    js  
    ├──  
    │  
    ├──  AppBootstrap.js  
    ├──  AppConstants.js  
    ├──  
    ├──  
    │  
    │  
    │  
    ├──  utils  
    │      ├──  AppWebAPIUtils.js  
    │      ├──  FooUtils.js  
    │      └──  __tests__  
    │              ├──  AppWebAPIUtils-­‐test.js  
    │              └──  FooUtils-­‐test.js  
    └──    
    !
    actions  
    └──  MessageActionCreators.js
    AppDispatcher.js
    stores  
    ├──  MessageStore.js  
    └──  __tests__  
           └──  MessageStore-­‐test.js
    views  
    ├──  MessageControllerView.react.js  
    └──  MessageListItem.react.js

    View Slide

  45. js  
    ├──  
    │  
    ├──  AppBootstrap.js  
    ├──  AppConstants.js  
    ├──  
    ├──  
    │  
    │  
    │  
    ├──  utils  
    │      ├──  AppWebAPIUtils.js  
    │      ├──  FooUtils.js  
    │      └──  __tests__  
    │              ├──  AppWebAPIUtils-­‐test.js  
    │              └──  FooUtils-­‐test.js  
    └──    
    !
    AppDispatcher.js
    views  
    ├──  MessageControllerView.react.js  
    └──  MessageListItem.react.js
    Dispatcher
    Action
    Store
    View
    actions  
    └──  MessageActionCreators.js
    stores  
    ├──  MessageStore.js  
    └──  __tests__  
           └──  MessageStore-­‐test.js

    View Slide

  46. Views & “Controller” Views
    View
    views  
    ├──  MessageControllerView.react.js  
    └──  MessageListItem.react.js

    View Slide

  47. Views & “Controller” Views
    Tree of React components
    Controller views are near the root, listen for change events
    On change, controller views query stores for new data
    With new data, they re-render themselves & children
    View in a Flux application are a tree of React components.
    Near the top of that tree, we have some special views that we call “controller” views - that’s a somewhat controversial name - they aren’t really controllers.
    Some people use the name containers, but I think a better name might be “querying views”. The thing that differentiates them is that they query the
    stores that have changed and provide that data to their children, and the data flows down the tree.

    View Slide

  48. Now let’s stop for a second and look at React.

    View Slide

  49. React & the DOM
    Component-based framework for managing DOM updates
    Uses a “Virtual DOM”: data structure and diff algorithm
    Updates the DOM as efficiently as possible
    Huge performance boost
    Bonus: we can stop thinking about managing the DOM
    Some people describe React as a component based framework for managing DOM updates.

    View Slide

  50. React’s Paradigm
    Based on Functional-Reactive principles
    Unidirectional data flow
    Composability
    Predictable, Reliable, Testable
    Declarative: what the UI should look like, given props
    React is more than that, however. The real innovation with React is its programming paradigm.
    The Virtual DOM is merely an implementation detail that helps to provide us with that paradigm.
    The really great thing about React is that it’s based on functional-reactive principles.
    !
    We can think of each function in React as being like a pure function in functional programming. And just like pure functions, we can compose them together, with the data output of
    each function leading into the next, in a unidirectional data flow.
    !
    And like pure functions, React components are very predictable, reliable and testable.
    !
    We can declare what our UI should look like, given any props.

    View Slide

  51. Using React
    Data is provided through props
    Rendering is a function of this.props and this.state
    Keep components as stateless as possible
    “Re-render” (or not) on every state change or new props
    Component lifecycle and update cycle methods
    Props are like the arguments of the component. They are how we provide data to the component.
    !
    And in fact rendering is a function of this.props and this.state. Props come from the outside, but state in an internal map of values.
    !
    But if we’re smart about it, we’ll avoid using this.state and we’ll keep our components as stateless as possible. This keeps our components pure, like pure functions: that is, we will
    always get the same result, given specific values for props.
    !
    We can also freely re-render at will — this complements Flux very nicely, as we can immediately see any changes in our application state reflected in our UI.
    !
    React also provides us with hooks into each component’s lifecycle and update cycles.

    View Slide

  52. var  MessagesControllerView  =  React.createClass({  
    !
       getInitialState:  function()  {  
           return  {  messages:  MessageStore.getMessages()  };  
       },  
    !
       componentDidMount:  function()  {  
           MessageStore.on('change',  this._onChange);  
       },  
    !
       componentWillUnmount:  function()  {  
           MessageStore.removeListener('change',  this._onChange);  
       },  
    !
       render:  function()  {  
           //  TODO  
       },  
    !
       _onChange:  function()  {  
           this.setState({  messages:  MessageStore.getMessages()  });  
       }  
    !
    });
    //  MessagesControllerView.react.js  
    Here is a component where I’m going to use four lifecycle methods to make it a controller view.

    View Slide

  53. var  MessagesControllerView  =  React.createClass({  
    !
       getInitialState:  function()  {  
           return  {  messages:  MessageStore.getMessages()  };  
       },  
    !
       componentDidMount:  function()  {  
           MessageStore.on('change',  this._onChange);  
       },  
    !
       componentWillUnmount:  function()  {  
           MessageStore.removeListener('change',  this._onChange);  
       },  
    !
         
         
         
    !
       _onChange:  function()  {  
           this.setState({  messages:  MessageStore.getMessages()  });  
       }  
    !
    });
       render:  function()  {  
           //  TODO  
       },
    //  MessagesControllerView.react.js  
    Here they are in yellow. I’m just using these methods to listen to the store, and to set up some initial state by pulling data from the store.
    !
    I’ll also create an onChange handler so that I can update that state. Whenever I call setState to update a React component’s state it will re-render itself and all of its children.

    View Slide

  54. render:  function()  {  
       var  messageListItems  =  this.state.messages.map(message  =>  {  
           return  (  
                               key={message.id}  
                   messageID={message.id}  
                   text={message.text}  
               />  
           );  
       });  
       return  (  
             
               {messageListItems}  
             
       );  
    },
    Now in the render method, we can map over the messages we’ve stored in this.state and create a child component — a list item — out of each one.
    !

    !
    provide unique key for arrays of children

    View Slide

  55. //  MessageListItem.react.js  
    !
    var  MessageActionCreators  =  require('MessageActionCreators');  
    var  React  =  require('react');  
    !
    var  MessageListItem  =  React.createClass({  
    !
       propTypes  =  {  
           messageID:  React.PropTypes.number.isRequired,  
           text:  React.PropTypes.string.isRequired  
       },  
    !
       render:  function()  {  
           return  (  
                 
                   {this.props.text}  
                 
           );  
       },  
    !
       _onClick:  function()  {  
           MessageActionCreators.messageDeleted(this.props.messageID);  
       }  
    !
    });  
    !
    module.exports  =  MessageListItem;
    Here’s our list item.
    It’s going to raise an error if we haven’t passed in the correct data as props.
    We could lift the hard requirement and show a spinner instead.
    onClick handler will be automatically handled by event delegation
    In that handler, we’ll call an action creator to express what the user has done.

    View Slide

  56. Dispatcher
    Action
    Store
    View
    messageDeleted:  messageID  =>  {  
       AppDispatcher.dispatch({  
           type:  ActionTypes.MESSAGE_DELETED,  
           messageID  
       });  
    }
    case  ActionTypes.MESSAGE_DELETED:  
       delete  _messages[action.messageID];  
       this.emit('change');  
       break;  
    _onChange:  function()  {  
       this.setState({    
           messages:  MessageStore.getMessages()    
       });  
    }
    Now we’ve come full circle.
    !
    First our action will get handed to the dispatcher by the action creator.
    Then our store will handle that action and emit change.
    Then our controller view will respond to the change event by querying for new data, and update itself and all of its children.

    View Slide

  57. Initialization of the App
    Usually done in a bootstrap module
    Initializes stores with an action
    Renders the topmost React component

    View Slide

  58. //  AppBootstrap.js  
    !
    var  AppConstants  =  require('AppConstants');  
    var  AppDispatcher  =  require('AppDispatcher');  
    var  AppRoot  =  require('AppRoot.react');  
    var  React  =  require('React');  
    !
    require('FriendStore');  
    require('LoggingStore');  
    require('MessageStore');  
    !
    module.exports  =  (initialData,  elem)  =>  {  
       AppDispatcher.dispatch({  
           type:  AppConstants.ActionTypes.INITIALIZE,  
           initialData  
       });  
       React.render(,  elem);  
    };

    View Slide

  59. Calling a Web API
    Use a WebAPIUtils module to encapsulate XHR work.
    Start requests directly in the Action Creators, or in the stores.
    Important: create a new action on success/error.
    Data must enter the system through an action.

    View Slide

  60. Immutable Data
    Boost performance in React’s shouldComponentUpdate()
    React.addons.PureRenderMixin
    immutable-js: http://facebook.github.io/immutable-js/

    View Slide

  61. More Flux Patterns
    LoggingStore
    Error handling with client ID / dirty bit
    Error handling with actions queue
    Resolving dependencies in the Controller-view

    View Slide

  62. Anti-patterns
    Application state/logic in React components
    Getters in render()
    Public setters in stores & the setter mindset trap
    Props in getInitialState()

    View Slide

  63. Flux
    Dataflow
    Programming CQRS
    Functional and FRP
    MVC
    Reactive

    View Slide

  64. FLUX
    TOTALLY
    WORKS
    Dispatcher
    Action
    Store
    View

    View Slide

  65. Thank You!
    https://speakerdeck.com/fisherwebdev/react-flux-fluent

    View Slide

  66. Thank You!
    https://speakerdeck.com/fisherwebdev/react-flux-fluent-2015
    http://facebook.github.io/immutable-js/
    http://facebook.github.io/react/
    http://facebook.github.io/jest/
    http://facebook.github.io/flux/

    View Slide