Flux is an architecture!

Designed at Facebook

Pattern

Agenda:

  • What is FLUX ?

  • Dispatcher

  • Action/Action Creator

  • Store

  • View

  • API

  • FLUX-Utils

  • MVC vs FLUX

The difficult part in this case is to actually keep in sync all these states with the DOM and vice versa, especially when dealing with asynchronicity.

MVC

MVC

is an architectural pattern that separates an application into three main logical components

M - Business logic data

V - Presents data from model

C - Responds to the user actions 

MVP

MVP is an evolution of MVC and it has multiple variants and implementations.

M - Data

V - Presents data from presenter

P - Business logic

MVVM

is an architectural pattern that separates an application into three main logical components

M - Data

V - Presents data from VM

VM - Business logic

The difficult part in this case is to actually keep in sync all these states with the DOM and vice versa, especially when dealing with asynchronicity.

MVC/MVP/MVVM

FLUX

Unidirectional data flow

 

 

 

 

 

 

 

It places a focus on creating explicit and understandable update paths for your application's data, which makes tracing changes during development simpler and makes bugs easier to track down and fix.

Dispatcher

// src/AppDispatcher.js
import { Dispatcher } from 'flux';

const AppDispatcher = new Dispatcher();

export default AppDispatcher;
AppDispatcher.dispatch({ 
    actionType: 'ADD_TODO', 
    value: { text: 'fix some issues' } 
});

AppDispatcher.register(payload => { 
    if (payload.actionType === 'ADD_TODO') {
        ...
    }
});

What is dispatcher ?

Action

// js/actions/TodoActions.js
AppDispatcher.dispatch({
    actionType: TodoConstants.ADD_TODO,
    value
});

Action Creator

// js/actions/TodoActions.js
import AppDispatcher from "../AppDispatcher";
import TodoConstants from "../constants/TodoConstants";

export default {
    addItem(value) {
        AppDispatcher.handleViewAction({
            actionType: TodoConstants.ADD_TODO,
            value
        });
    }
};

Constants

// constants/TodoConstants.js

export default {
    ADD_TODO: 'ADD_TODO'
};

Store

import { EventEmitter } from 'events';
import uuid from 'uuid';
import assign from 'object-assign';

import AppDispatcher from '../AppDispatcher';
import TodoConstants from '../constants/TodoConstants';

const CHANGE_EVENT = 'change';

const _todos = [];

function addTodo(text) {
    _todos.push({ id: uuid(), text });
}

const TodoStore = assign({}, EventEmitter.prototype, {
    getAll: function() {
        return _todos;
    },
    addChangeListener(callback) {
        this.on(CHANGE_EVENT, callback);
    },
    removeChangeListener(callback) {
        this.removeListener(CHANGE_EVENT, callback);
    },
    emitChange() {
        this.emit(CHANGE_EVENT);
    }
});

AppDispatcher.register(({ action: { text, actionType } }) => {
    switch(actionType) {
        case TodoConstants.ADD_TODO:
            addTodo(text);
            TodoStore.emitChange();
            break;
    }
});

export default TodoStore;

View

import React, { Component } from 'react';
import autobind from 'autobind-decorator';

import TodoStore from '../stores/TodoStore';
import TodoActions from '../actions/TodoActions';

class TodoComponent extends Component {
    constructor(props) {
        super(props);
        this.state = { value: '' };
    }
    componentDidMount() {
        TodoStore.addChangeListener(this.handleClear);
    }
    componentWillUnmount() {
        TodoStore.removeChangeListener(this.handleClear);
    }
    @autobind handleClear() {
        this.setState({ value: '' });
    }
    @autobind handleChange({ target: { value } }) {
        this.setState({ value });
    }
    @autobind handleClick(e) {
        e.preventDefault();

        const { state: { value } } = this;

        value && TodoActions.addTodo(value);
    }
    @autobind handleAsyncClick(e) {
        e.preventDefault();

        const { state: { value } } = this;

        value && TodoActions.addAsyncTodo(value);
    }
    renderTodo() {
        return TodoStore.getAll().map(({ value, id}) => (
            <li key={ id } data-id={ id }>{ value }</li>
        ));
    }
    render() {
        const todo = this.renderTodo();
        return (
            <div>
                <form>
                    <input value={ this.state.value } onChange={ this.handleChange } />
                    <button onClick={ this.handleClick }>add todo</button>
                </form>
                <ul> { todo } </ul>
            </div>
        );
    }
}

export default TodoComponent;

What about async ?

 

and

 

Can we simplify our code ?

flux-utils

flux it's not only a dispatcher!

MVC vs Flux

Questions ?

flux

By Sarhan Azizov

flux

  • 641