flux is an architecture, which is used to build for front-end UIs.
Links:
- npm package link
- the official site link
- GitHub link
- the GitHub examples page link
- very good video tutorial link
Content table
The flux diagrams


The flux pattern is unidirectional, so the data flow goes to one direction.
To understand how flux works better look at the code, than reading theory.
Working flux example
The code on the GitHub link
We will create a simple user list with remove and add buttons, one input field, and output list user.
The app should have such a folder structure
We need to create actions that will include in any file and fire events
src/actions/UserActions.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import AppDispatcher from '../dispatcher/AppDispatcher' import { data as AppConstants } from '../constants/AppConstants' const UserActions = { addUser(user) { AppDispatcher.dispatch({ type: AppConstants.ADD_USER, user: user, }) }, removeUser(id) { AppDispatcher.dispatch({ type: AppConstants.REMOVE_USER, id: id, }) } } export default UserActions |
Here is a standard React container UserList where we use UserActions to change the store by calling its functions. The methods componentDidMount and componentWillUnmount are used for passing the callbacks to the store to listen to the events when the store when it is updated and respectively change the views by calling this.setState function of the state. It’s two are a very important part in all our flux structure
src/components/UserList.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
import React from 'react' import UserStore from '../stores/UserStore' import UserActions from '../actions/UserActions' import { data as AppConstants } from '../constants/AppConstants' class UserList extends React.Component { constructor(props) { super(props) this.state = { users: UserStore.getAllUsers(), user: null, } this.onChangeInput = this.onChangeInput.bind(this) this.onClickAddUser = this.onClickAddUser.bind(this) this.onClickRemoveUser = this.onClickRemoveUser.bind(this) this.handleAddUser = this.handleAddUser.bind(this) this.handleRemoveUser = this.handleRemoveUser.bind(this) } componentDidMount() { UserStore.addChangeListener( AppConstants.ADD_USER, this.handleAddUser) UserStore.addChangeListener( AppConstants.REMOVE_USER, this.handleRemoveUser) } componentWillUnmount() { UserStore.removeChangeListener( AppConstants.ADD_USER, this.handleAddUser) UserStore.removeChangeListener( AppConstants.REMOVE_USER, this.handleRemoveUser) } handleAddUser() { this.setState({ users: UserStore.getAllUsers(), }) } handleRemoveUser() { this.setState({ users: UserStore.getAllUsers(), }) } onChangeInput(e) { this.setState({ user: e.target.value }) } onClickAddUser(e) { console.log(this.state.user); UserActions.addUser(this.state.user) } onClickRemoveUser(e) { let id = e.target.attributes.id.value console.log('id = ', id); UserActions.removeUser(id) } render() { let users = '' if(this.state){ users = this.state.users.map((e, ind) => { return ( <li key={ind}> {e.user} <button onClick={this.onClickRemoveUser} id={e.id} >remove</button> </li> ) }) } return ( <div> <h1>User lists:</h1> <ul> {users} </ul> <input type="text" onChange={this.onChangeInput} /> <br /> <button onClick={this.onClickAddUser} >Add</button> </div> ) } } export default UserList |
The constants for the events we store in a separated file
src/constants/AppConstants.js
1 2 3 4 5 6 7 8 |
import keyMirror from 'keymirror' const data = keyMirror({ ADD_USER: null, REMOVE_USER: null, }) export { data } |
We have to use dispatcher that will work as a pub/sub mechanism deliver actions to the database stores
src/dispatcher/AppDispatcher.js
1 2 3 |
import { Dispatcher } from 'flux' export default new Dispatcher() |
A UserStore is a file where we save all our state data. Here we use a standard node.js events module to derive from EventEmitter the store. The users is in a global module scope and available to any functions, so we use AppDispatcher.register to receive actions from whatever and respectively of them handle the store.
src/stores/UserStore.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
import { EventEmitter } from 'events' import uuid from 'uuid/v4' import AppDispatcher from '../dispatcher/AppDispatcher' import { data as AppConstants } from '../constants/AppConstants' let users = [ { id: uuid(), user: "user111", }, { id: uuid(), user: "user2", }, { id: uuid(), user: "user3", } ] const UserStore = Object.assign({}, EventEmitter.prototype, { getAllUsers() { return users }, emitAddUser() { this.emit(AppConstants.ADD_USER) }, emitRemoveUser() { this.emit(AppConstants.REMOVE_USER) }, addChangeListener(event, callback) { this.on(event, callback) }, removeChangeListener(event, callback) { this.removeListener(event, callback) } }) AppDispatcher.register((action) => { switch (action.type) { case undefined: {break} case AppConstants.ADD_USER: { console.log(AppConstants.ADD_USER); users.push({ id: uuid(), user: action.user, }) UserStore.emitAddUser() break } case AppConstants.REMOVE_USER: { console.log(AppConstants.REMOVE_USER); for (let i = 0; i < users.length; i++) { if (users[i].id === action.id) { users.splice(i, 1) UserStore.emitRemoveUser() break; } } break; } default: {} } }) export default UserStore |
To hook the app to the DOM we use index.js file
src/index.js
1 2 3 4 5 6 7 8 9 |
import React from 'react' import ReactDOM from 'react-dom' import UserList from './components/UserList' ReactDOM.render( <UserList />, document.getElementById('root') ) |
the end