Fluxy

Fluxy (adj): characteristics inherited / inspired by Facebook's Flux Architecture

Fluxy and Flux refer to the pattern

not specifically Facebook's Flux implementation

throughout this presentation...

What is the Flux Pattern?

What is Flux?

  • more of a pattern or architecture rather than a formal framework
  • vs. a MV* pattern
  • creating a shift in the front-end landscape (and beyond)
  • popularized by Facebook's Flux & React
  • not Facebook Flux & React specific; many possible implementations
    • Flux, Reflux, Redux, Fluxxor, etc
    • React, Riot, etc
    • with superhuman discipline, you could implement it in about anything (even NG) ;-)

Why a New Pattern?

Why not traditional MV*?

https://facebook.github.io/flux/docs/overview.html

http://fluxxor.com/what-is-flux.html

abnormally simple MVC

model

view

controller

action

  • arrows represent an interaction between the different parts of the system
  • an action invokes some functionality in the controller
  • the controller potentially updates the model
  • the model changes are reflected in the view
  • user interaction in the view can change the model directly (2-way binding) or kickoff an action.

Adding a Couple of Views

https://facebook.github.io/flux/docs/overview.html

http://fluxxor.com/what-is-flux.html

abnormally simple MVC

model

view

controller

action

view

view

Adding Another Model

https://facebook.github.io/flux/docs/overview.html

http://fluxxor.com/what-is-flux.html

abnormally simple MVC

model

view

controller

action

view

view

model

Approaching Real World Conditions

https://facebook.github.io/flux/docs/overview.html

http://fluxxor.com/what-is-flux.html

still a pretty simple MV*

model

view

model

view

model

view

model

view

model

view

model

view

model

view

controller

controller

No 2-Way Binding?

https://facebook.github.io/flux/docs/overview.html

http://fluxxor.com/what-is-flux.html

still a pretty simple MV*

model

view

model

view

model

view

model

view

model

view

model

view

model

view

controller

controller

still problematic at scale

prone to bugs

that are hard to debug

hard for humans to reason with

Scope Creep

model

view

model

view

model

view

model

view

model

view

model

view

model

view

to fully understand this

<---------

{

you must understand all this

and know all the places where state can be mutated

}

and maybe this

and potentially how

controller

and maybe this

Banana vs Jungle

maybe these

difficult

  • to undertand
  • when inheriting such a project
  • to onboard new devs
  • to maintain
  • to add new features
  • to test
  • etc

How is Flux Different?

How is Flux Different?

1. Unidirectional Data Flow

"Data Flows Down"

view

model

{}

</>

  • subscribes to store
  • reacts to store's state
  • stateless*
  • can't change itself directly*
    • no imperative manipulations
  • a pure function of state
    • no scope creep
  • contains the model
  • the model can't be changed directly
  • allows subscribers
  • notifies listeners when changes to state occur

store

view

store

{}

</>

smart component

</>

</>

</>

dumb components

  • subscribes to store
  • reacts to store's state
  • stateless*
  • can't change itself directly*
  • a pure function of state
  • composes dumb components
  • aka: Controller-Views
  • contains the entire apps' state / view-model
  • immutable or not directly mutable
  • notifies listeners when changes to state occur
  • 100% decoupled*
    • from store, smart component, each other
  • pure / reactive
  • reusable
  • composable
  • all dependencies injected via props*

view

all completely reactive to store

export default ({ people }) => {

    let list = people.map( person => (
        <li>
            <strong>{ person.name }</strong>
            : <small>{ person.about }</small>
        </li>
    ));
	
    return people.length
        ? <ul>{ list }</ul>
        : <strong>No Peeps</strong>;

};

Dumb Component (JSX)

  • No Dependencies 

https://jsbin.com/qeguge/edit?js,output

{}

</>

</>

</>

</>

Pop Quiz

How do I change the rendered UI of this component?

Change the state in the store.

Okay, so how do you change the state in the store?

How is Flux Different?

2. Store vs Model

Store

  • contains the model / state
    • is a plain old JS object (POJO)
    • single source of truth
      • only place in app where state is kept
  • contains the logic to change its state
    • predefined list of all mutations called Action Handlers (or reducers)
    • mutations are always synchronous
  • listens for and reacts to dispatched Actions
    • no traditional getters / setters
    • change requests are broadcasted in
    • can't mutate state in any other way
  • emits notifications to subscribers when changes occur
  • -------
  • -------
  • -------

{}

Store

model / state

notifier

action handler(s)

listener

regarding the store: as an app dev, you only write action handlers

  • -------
  • -------
  • -------

{}

Actions

  • plain old JavaScript object (POJO)
  • type key names the mutation
    • only required key
    • unique across app (or collisions)
  • the rest of the structure is up to you
    • minimalism recommended
{
    "type": "ADD_PERSON",
    "name": "Jared",
    "location": "South Jordan, UT",
    "food": ["pizza", "bacon"]
}

example action

action handler

to understand action handlers, let's talk...

Actions & Handlers

{
    "type": "INCREMENT_COUNTER"
}
function myCounter(state=0, action) {
    switch(action.type) {
        case "INCREMENT_COUNTER":
            return state+1;
        case "DECREMENT_COUNTER":
            return state-1;
        default:
            return state;
    }
}
  • usually a switch statement
  • checks for a matching`action.type`
  • optionally performs the mutation

action handler

action

  • asks store to make a mutation, hangs up
  • blissfully ignorant
    • current state
    • how mutations occurs
    • if mutation occurs

Example Store (Redux)

import { createStore } from 'redux'


function todos(state = [], action) {
    switch (action.type) {
        case 'ADD_TODO':
            return state.concat({
                task: action.item,
                id: state.length+1
            }); 

        case 'REMOVE_TODO':
            return state.filter(item=>item.id!==action.id);

        default:
            return state
    }
}

let store = createStore(todos);

store.subscribe( () => console.log(
    store.getState()
));

https://jsbin.com/quyotan/edit?js,console

How is Flux Different?

3. Actions Float Up

  • -------
  • -------
  • -------

{}

store

action creators

</>

</>

</>

</>

view

action

handlers

state

notify

smart component

dumb components

What's Missing?

dispatched action

listener

action creator

Action Creators

  • a function which returns an action object
  • abstracts away the details of the action object structure
  • where you'd find async code that talks to servers
  • it's the upstream glue between the store and smart-components

dispatched action

Action Creators

export function addTodo(text) {
    return {
        type: ADD_TODO,
        text
    };
}


http://rackt.org/redux/docs/basics/Actions.html

import { dispatch } from './store.js';
import { addTodo } from './actions/add-todo.js';
import { Dumb } from './components/dumb.js';

// to be passed into dumb component(s)
let add = text => (
    dispatch( addTodo(text) )
);

// later usage:
<Dumb addAction={add} />

../actions/add-todo.js

./some/smart-component.js

How is Flux Different?

4. Distinct, Composable Parts

Quick Poll

  • -------
  • -------
  • -------

{}

</>

</>

</>

</>

action

handlers

smart component

dumb components

action

listener

action creator

state

notifier

who believes they:

  • decently understand this whole system?
  • are ready to write a fluxy app now (if provided a project-starter)?
  • understand parts, but are still making the connections?
  • are completely lost?

you know what's awesome?

you don't need to understand the whole jungle to start writing bananas!

  • -------
  • -------
  • -------

{}

</>

</>

</>

</>

action

handlers

smart component

dumb components

action

listener

action creator

state

notifier

Of this system, these are the things you write

  • action creator(s)
  • action handler(s)
  • smart components
  • dumb components
  • -------
  • -------
  • -------

{}

</>

</>

</>

</>

action

handlers

smart component

dumb components

action

listener

action creator

state

notifier

Action Handlers & Dumb Components

  • are blissfully ignorant of any other part of the jungle
  • provided a few rules, any developer* could start writing these today
  • are pure functions & have no library dependencies
  • it may be preferable to write these without knowledge of any other part of the app
  • are application agnostic / extremely reusable
  • -------
  • -------
  • -------

{}

</>

</>

</>

</>

action

handlers

smart component

dumb components

action

listener

action creator

state

notifier

Action Creator

  • no coupling, high cohesion
    • only need to know emitted action's structure
  • more app specific, but decoupled enough for potential reusability
  • also export their functionality

thus, requires some awareness of the system

  • -------
  • -------
  • -------

{}

</>

</>

</>

</>

action

handlers

smart component

dumb components

action

listener

action creator

state

notifier

Smart Component / Controller-View

  • it imports the store to which it subscribes
  • it imports and composes dumb components
  • it imports and composes actions
  • subscribes to the store
  • disperses data and actions to dumb components
  • is app specific
  • essentially is just a smart composition

Distinct Units

  • reusable
  • repeatable
  • extensible
  • composable
  • SRP
  • pure function
  • encapsulated
  • swappable

each unit is:

  • TESTABLE!

How is Flux Different?

5. Scales Gracefully

FTW

Fluxy Scalability

  • -------
  • -------
  • -------

{}

</>

</>

</>

</>

action

handlers

smart component

dumb components

action

listener

action creator

state

notifier

start with

  • 2 action creators
  • 1 action handler / reducer
  • 1 smart component
  • 3 dumb components
  • -------
  • -------
  • -------

{}

</>

</>

</>

</>

action

handlers

smart component

action

listener

action creator

state

notifier

</>

</>

</>

</>

</>

</>

Add Dumb Components

no effect on system complexity

  • -------
  • -------
  • -------

{}

</>

</>

</>

</>

action

handlers

smart component

action

listener

action creator

state

notifier

</>

</>

</>

</>

</>

</>

Add Smart Components

</>

</>

no effect on system complexity

  • -------
  • -------
  • -------

{}

</>

</>

</>

</>

action

handlers

smart component

action

listener

action creator

state

notifier

</>

</>

</>

</>

</>

</>

Add Action Handlers 

may result in more action creators

  • -------
  • -------
  • -------
  • -------
  • -------
  • -------
  • -------
  • -------
  • -------

but no increase in system complexity

</>

</>

so, as your app grows bigger...

complexity

does not!!

Other Visual Representations

per Google Image search ;)

action

view

store

dispatch

action creator

smart component

store

dispatch

dumb component

api

user

interaction

a playground

https://jsbin.com/sagafug/edit?js,output