Flux is Dead. Long Live Flux!

Alexey Raspopov, DataRobot.

Flux is dead.
Long live Flux!

$ whoami

A year of hype!

			render = (Data) => UI;
			update = (State, Action) => NewState;
		
			Actions = [Update This, Add That, Delete Shit, ...];
			AppState = Actions.reduce(update, InitialState);
			AppState.subscribe(render);
		

The only thing that didn't change!

So hot back in 2015

Dead!

Where is the
hype train now?

Redux?

False God

:scream:

Unlike Flux, Redux does not have the concept of a Dispatcher. This is because it relies on pure functions instead of event emitters, and pure functions are easy to compose and don’t need an additional entity managing them.

Redux Docs
			const Store = Redux.createStore(...);
			Store.dispatch(action);
			Store.subscribe(() => ...);
		
			const Dispatcher = new Flux.Dispatcher();
			Dispatcher.dispatch(action);
			Dispatcher.register(() => ...);
		

If you’re coming from Flux, there is a single important difference you need to understand. Redux doesn’t have a Dispatcher or support many stores. Instead, there is just a single store with a single root reducing function. As your app grows, instead of adding stores, you split the root reducer into smaller reducers independently operating on the different parts of the state tree.

Redux Docs

Instead of
adding stores,
you add reducers

:unicorn_face: :rainbow:

Redux evolves the ideas of Flux, but avoids its complexity by taking cues from Elm. Whether you have used them or not, Redux only takes a few minutes to get started with.

Redux Docs

Horizontal vs Vertical Surface Area

Horizontal surface areathe number of components in your application layer, component layer, layout layer, rendering layer.

Vertical surface areathe number of layers for a feature.

Verticals are fixed. Horizontal grows with app complexity.

Redux verticals

Flux verticals

Always remains the same.

npm i --save flux

@2.1.1

			import { Dispatcher } from 'flux';
			import { Container, ReduceStore } from 'flux/utils';
		

"A lot of boilerplate"
they said!

			import { Dispatcher } from 'flux';
			export default new Dispatcher();
		

Do not
underestimate essential patterns!

npm i --save immutable

Essential patterns

  1. Define immutable data structures for domain models
			const Shape = { firstName: 'John', lastName: 'Doe',
			                age: 0, isActive: true };
			 
			class UserRecord extends Record(Shape) {
			
			}
		

Essential patterns

  1. Define immutable data structures for domain models
  2. Provide Web API (Data Access Object pattern)
			class Users {
			  async create(data) { ... }
			  async retrieve(id) { ... }
			  async update(id, data) { ... }
			  async destroy(id) { ... }
			}
		

All methods return immutable record defined before.

Essential patterns

  1. Define immutable data structures for domain models
  2. Provide Web API (Data Access Object pattern)
    • Use async actions as much as possible
			class Users {
			  async retrieve(id) {
			    try {
			      const response = await get(`/users/${id}`);
			      const user = await response.json();
			 
			      return new UserRecord(user);
			    } catch (error) {
			      throw new AccessError('Oops');
			    }
			  }
			}
		
			class UserListStore extends ReduceStore {
			
			
			}
		
			export default new UserListStore(Dispatcher);
		

Relationships

Essential patterns

  1. Define immutable data structures for domain models
  2. Provide Web API (Data Access Object pattern)
    • Use async actions as much as possible
  3. Provide getter methods in your stores
			class UserListStore extends ReduceStore {
			  // ...
			  getOnlineUsersCount() {
			    return this.getState().count(u => u.isOnline);
			  }
			  // ...
			}
		

Essential patterns

  1. Define immutable data structures for domain models
  2. Provide Web API (Data Access Object pattern)
    • Use async actions as much as possible
  3. Provide getter methods in your stores
  4. Dispatch errors as separate actions that should be handled as well
			async function retrieveUser(id) {
			  try {
			    const user = await users.retrieve(id);
			    Dispatcher.dispatch({ type: USER_RETRIEVED,
			                          id, user });
			  } catch (error) {
			    Dispatcher.dispatch({ type: USER_RETRIEVE_FAILED,
			                          error });
			  }
			}
		

There should be one— and preferably only one —obvious way to do it.

Tim Peters, The Zen of Python

Special cases aren't special enough to break the rules.

Tim Peters, The Zen of Python
			class UserListContainer extends React.Component {
			
			
			
			}
		
			export default Container.create(UserListContainer);
		
			function getStores() {
			  return [UserListStore];
			}
			 
			function calculateState() {
			  const users = UserListStore.getUsers();
			  const onlineCount = UserListStore.getOnlineUsersCount();
			  return { users, onlineCount };
			}
			 
			export default Container.create(UserList,
			                                getStores,
			                                calculateState);
		

@3.0.0

Soon™

What's new?

That's all?

That's enough!

Thank you!

Link to these slides — alexeyraspopov.github.io/long-live-flux/