Designed at Facebook
Pattern
Agenda:
What is FLUX ?
Dispatcher
Action/Action Creator
Store
View
API
FLUX-Utils
MVC vs FLUX
is an architectural pattern that separates an application into three main logical components
MVP is an evolution of MVC and it has multiple variants and implementations.
is an architectural pattern that separates an application into three main logical components
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.
// 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') {
...
}
});// js/actions/TodoActions.js
AppDispatcher.dispatch({
actionType: TodoConstants.ADD_TODO,
value
});// 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/TodoConstants.js
export default {
ADD_TODO: 'ADD_TODO'
};
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;
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;