This is a todo example of Facebook's official learning Flux.
Want to use this example to summarize how to build an App with React and Flux from scratch
StructureApp
├─ javascripts
│ ├─ actions
│ │ ├─ TodoActions.js
│ ├─ components
│ │ ├─ TodoComponents
│ │ │ ├─ TodoApp.js
│ │ │ ├─ Header.js
│ │ │ ├─ MainSection.js
│ │ │ ├─ Footer.js
│ │ │ ├─ TodoItem.js
│ │ │ ├─ TodoTextInput.js
│ ├─ constants
│ │ ├─ TodoConstants.js
│ ├─ dispatcher
│ │ ├─ AppDispatcher.js
│ ├─ stores
│ │ ├─ TodoStore.js
├─ stylesheets
│ ├─ TodoStyle.css
├─ index.html
├─ README.md
├─ package.json
├─ webpack.config.js
Perhaps the structure you see will be a bit different from the official demo, because the official demo itself only has the function of todo, but it is actually far from it. So under components, what parts are subdivided, like TodoComponents
If you don't understand the concepts of Action, Dispatcher, Store and Controller View in Flux, you can take a look at these two articles
Flux For Stupid People38
Getting To Know Flux, the React.js Architecture25
Components
First you determine your components through the interface of your app, such as
From this figure we can see that our components have
Header
MainSection
Footer
TodoItem
TodoTextInput
TodoTextInput in MainSection is when we double-click on our existing todo to update it
Actions
After identifying the components, we can determine our TodoActions file.
How many actions are there for this Todo app?
create-we can create a new todo
updateText-Double-click an existing todo to update it
toggleComplete-Did you see every previous tick? Just to give you a decision
toggleCompleteAll-Did you see the one in front of the input box? Is to let you complete all or not at all
destroy-Did you see the fork behind each one? I only want to see what hover sees above, this is for you to delete this one
destroyCompleted-Did you see the Clear completed under Footer? Is to delete the completed todo for us
That's it. We define different action functions in this file according to our needs, but the functions here don't involve logical processing. The functions here just tell our Dispatcher what operation the user has performed. So we only need to pass an object to the Dispatcher, and a necessary attribute in the object is actionType. If the user has the parameters passed to us for this operation. That parameter will also be placed in this object.
For example, the user wants to create a new todo, which is our create action
import AppDispatcher from ‘../dispatcher/AppDispatcher’; import TodoConstants from ‘../constants/TodoConstants’; var TodoActions = {
create (text) {
AppDispatcher.dispatch ({
actionType: TodoConstants.TODO_CREATE,
text: text
});
}, // other actions} export default TodoActions;
When we execute the AppDispatcher.dispatch method and pass him an object with the actionType attribute, he will shout, "Someone did an operation, this operation is xxx (the value of actionType), and brought a Parameters, which one do you deal with? "
Um, that ’s it, the data is transferred from Action to Dispatcher
Dispatcher
The specific implementation of Dispatcher can be found at github.com/facebook/flux/blob/master/src/Dispatcher.js
Visitors can only post two links, I am also drunk
When we use the Dispatcher provided to us by Facebook, everything will become a lot easier
npm install --save flux
import Flux from ‘flux’; var Dispatcher = Flux.Dispatcher; export default new Dispatcher ();
Dispatcher throughout the application
Only one, only one, only one
Someone said, your Dispatcher is only responsible for shouting, I do n’t want you, it seems okay. Hmm, it ’s not called Fulx, it ’s called Reflux github.com/spoike/refluxjs
Constants
Just now we saw that in our Actions, actionType: TodoConstants.TODO_CREATE, this TodoConstants is actually the name of our operation, equivalent to a constant, defined in Constants for easy management and call only.
Generally, as many actions as you have, there are as many constants in this Constants
KeyMirror is to create an object whose key value is equal to the name of the key--
Stores
The protagonist appears! But what is Store?
Store is a place to save data
var _todo = {};
Store is a place full of logic
The logical processing of all actions will happen here. Like our create action
function create (text) {var id = (new Date () + Math.floor (Math.random () * 999999)). toString (36);
_todos [id] = {
id: id,
complete: false,
text: text
};
}
Store is a place to respond to Dispatcher's cry
"Someone did an operation, this operation is xxx (the value of actionType), and also brought a parameter, which one of you will handle it?"
In the Store, we "register" a callback function through the Dispatcher. Whenever we call the dispatch function, that is, when the Dispatcher yells, we call our different logic processing functions according to different actionTypes, like this
import AppDispatcher from ‘../dispatcher/AppDispatcher’; import TodoConstants from ‘../constants/TodoConstants’;
AppDispatcher.register ((action) => {var text; switch (action.actionType) {case TodoConstants.TODO_CREATE:
text = action.text.trim (); if (text! == ‘‘) {
create (text);
TodoStore.emitChange ();
} break; // other case}
});
Store is a place to urge Controller View to change
Whenever the store changes the data, he needs the Controller View to follow him. They also agreed on a secret code
var CHANGE_EVENT = ‘change’;
Store told Controller View that when I shouted "change", after you heard it, you told your men to change together.
Controller View said yes.
But the Store will not shout and the Controller View will not hear it.
So the store learned to shout from EventEmitter and bought hearing aids for Controller View
import assign from ‘object-assign’; var EventEmitter = require (‘events‘). EventEmitter; var TodoStore = assign ({}, EventEmitter.prototype, {
areAllComplete () {for (var id in _todos) {if (! _todos [id] .complete) {return false;
}
} return true;
},
getAll () {return _todos;
},
emitChange () {this.emit (CHANGE_EVENT);
},
addChangeListener (callback) {this.on (CHANGE_EVENT, callback);
},
removeChangeListener (callback) {this.removeListener (CHANGE_EVENT, callback);
}
}); export default TodoStore;
So whenever the logic processing function is executed, Store will shout TodoStore.emitChange ();
Hearing aid addChangeListener (callback) {this.on (CHANGE_EVENT, callback)} I also bought it. If it is unsuccessful, it depends on Controller View
Controller View
In Components, you can't see the TodoApp component, because for the Todo app, the TodoApp component is Contriller View, and he controls all the Components.
But the important thing is, how did he bring the hearing aid that the Store bought him?
componentDidMount () {
TodoStore.addChangeListener (this._onChange.bind (this));
}
When the component is rendered, the store's addChangeListener is bound and its own onChange method is called back.
_onChange () {this.setState (this.getTodoState.bind (this) ());
}
Store shouted, after Controller View heard it, updated all the data and passed it to his men in the form of props-the Components he controlled
Summary
Now let's sort out the whole process (as far as create is concerned)
The user enters the todo to be added, and upon hitting Enter, the onKeydown method is triggered.
onKeydown calls the onSave method, and onSave calls the TodoActions.create method.
TodoActions.create triggered the AppDispatcher.dispatch method, AppDispatcher shouted.
TodoStore response, according to actionType called the create logic processing function. After the execution, it shouted "change".
Controller View heard with a hearing aid and then updated the data, and passed the data to the various components.
Re-rendered and added.
The above is my simple understanding, if there are errors, please correct me:)
[Tianying Jinchuang] React flux nine shallow one deep