In the past year, the front-end technology development, the most dazzling star is react.
React itself involves only the UI layer, and if you build large applications, you must match a front-end frame. In other words, you must learn at least two things in order to basically meet the needs: React + front-end frame.
Facebook is officially using the Flux framework. This article describes how to use Flux to organize your code and arrange internal logic on React basis, making your application easier to develop and maintain.
Before reading this article, I assume you have mastered the React. If not, you can read my "React introductory tutorial" first. As before, the goal of this article is to use the simplest language, the best-understood example, to give you a look.
First, what is Flux?
Simply put, Flux is an architectural idea that specifically solves the structural problems of software. It's the same kind of thing as the MVC architecture, but it's simpler and clearer.
There are many implementations of flux (at least 15), and this article uses the official Facebook implementation.
Second, install the Demo
For ease of interpretation, I wrote a demo.
Please install it first.
$ git clone https://github.com/ruanyf/extremely-simple-flux-demo.git$ cd Extremely-simple-flux-demo && NPM install$ NPM Start
Then, Access http://127.0.0.1:8080.
You'll see a button. This is our demo.
Iii. Basic Concepts
Before you explain the code, you need to know some basic concepts of Flux.
First, flux divides an application into four parts.
- View: Views Layer
- Action: Messages emitted by the view layer (e.g. MouseClick)
- Dispatcher(Dispatcher): Used to receive actions, execute callback functions
- store(data layer): Used to store the status of the application, in the event of a change, remind the views to update the page
Flux's greatest feature is the "one-way flow" of data.
- User Access View
- View issues the user's Action
- Dispatcher received Action to request the Store to update accordingly
- After the Store update, issue a "change" event
- Update page after View receives "change" event
In the above process, the data is always "one-way Flow", no adjacent part of the data "two-way flow." This ensures the clarity of the process.
Read here, you may feel confused, OK, this is normal. Next, I'll explain each step in detail.
Iv. View (Part I.)
Please open the Demo homepage index.jsx, you will see that only one component is loaded.
Index.jsxvar React = require (' React '); var reactdom = require (' react-dom '); var Mybuttoncontroller = require ('./ Componhttp://bjxykdhk.ebdoor.com/ents/mybuttoncontroller '); Reactdom.render ( <mybuttoncontroller/>, document.queryselector (' #example '));
In the above code, you may notice that the name of the component is not MyButton, but Mybuttoncontroller. Why is that?
Here, I am using the Controller view mode of React. The Controller view component is used only to save the state and then forward it to the child component. The source code of Mybuttoncontroller is very simple.
Components/mybuttoncontroller.jsxvar React = require (' React '); var buttonactions = require ('.. /actions/buttonactions ') var MyButton = require ('./mybutton '); var Mybuttoncontroller = React.createclass ({ Createnewitem:function (event) { Buttonactions.addnewitem (' new item '); }, render:function () { return <mybutton Onclick={this.createnewitem} />; }}); Module.exports = Mybuttoncontroller;
In the above code, Mybuttoncontroller passes the parameter to the subassembly mybutton. The latter source code is even simpler.
Components/mybutton.jsxvar React = require (' React '); var MyButton = function (props) { return <div> < Button Onclick={props.onclick}>new item</button> </div>;}; Module.exports = MyButton;
In the above code, you can see that mybutton is a pure component (that is, without any state), which facilitates testing and reuse. This is the biggest advantage of the "Controll View" mode.
MyButton has only one logic, that is, once the user clicks, call the This.createnewitem method and send an action to dispatcher.
COMPONENTS/MYBUTTONCONTROLLER.JSX //... Createnewitem:function (event) { Buttonactions.addnewitem (' new item '); }
In the above code, calling the Createnewitem method triggers an action named AddNewItem.
V. Action
Each action is an object that contains a ActionType property (which describes the type of action) and some other properties (used to pass the data).
In this demo, the Buttonactions object is used to store all action.
Actions/buttonactions.jsvar Appdispatcher = require ('.. /dispatcher/appdispatcher '), var buttonactions = { addnewitem:function (text) { Appdispatcher.dispatch ({ actiontype: ' Add_new_item ', text:text }); };
In the above code, the Buttonactions.addnewitem method uses Appdispatcher to distribute the action Add_new_item to the store.
Liu, Dispatcher
Dispatcher's role is to distribute the action to the Store,. You can think of it as a router that is responsible for establishing the correct route of Action between the View and the Store. Note that Dispatcher can only have one, and is global.
Facebook official Dispatcher Implementation output A class, you want to write a appdispatcher.js, generate Dispatcher instance.
Dispatcher/appdispatcher.jsvar dispatcher = require (' Flux '). Dispatcher;module.exports = new Dispatcher ();
The Appdispatcher.register () method is used to register various action callback functions.
Dispatcher/appdispatcher.jsvar Liststore = require ('.. /stores/liststore '); Appdispatcher.register (action) { switch (action.actiontype) {case ' Add_new_item ': Liststore.addnewitemhandler (action.text); Liststore.emitchange (); break; Default: //No OP }})
In the above code, dispatcher receives the Add_new_item action, executes the callback function, and operates on the Liststore.
Remember, Dispatcher is only used to distribute Action, there should be no other logic.
Seven, Store
Store stores the status of the entire app. Its role is somewhat like the model in the MVC architecture.
In our Demo, there is a liststore, where all the data is stored.
Stores/liststore.jsvar Liststore = { items: [], getall:function () { return this.items; }, Addnewitemhandler:function (text) { this.items.push (text); }, emitchange:function () { this.emit (' Change ');} ; Module.exports = Liststore;
In the above code, Liststore.items is used to save the entry, Liststore.getall () is used to read all entries, and Liststore.emitchange () is used to emit a "change" event.
Because the Store needs to send a "change" event to the View after the changes, it must implement the event interface.
Stores/liststore.jsvar Eventemitter = require (' Events '). Eventemitter;var assign = require (' object-assign '); var Liststore = assign ({}, Eventemitter.prototype, { items: [],< C2/>getall:function () { return this.items; }, addnewitemhandler:function (text) { This.items.push ( text); }, emitchange:function () { this.emit (' change '); }, addchangelistener:function ( Callback) { this.on (' Change ', callback); }, Removechangelistener:function (callback) { This.removelistener (' Change ', callback); });
In the above code, Liststore inherits Eventemitter.prototype, so you can use Liststore.on () and Liststore.emit () to listen and trigger events.
The event (This.emitchange ()) emitted after the Store update (This.addnewitemhandler ()) indicates that the status has changed. When the View Monitor hears this event, it can query the new status and update the page.
Viii. View (Part II)
Now, let's go back and modify the View so that it listens to the Store's Change event.
//Components/mybuttoncontroller.jsxvar React = require (' React '); var liststore = require ('.. /stores/liststore '); var buttonactions = require ('.. /actions/buttonactions ') var MyButton = require ('./mybutton '); var Mybuttoncontroller = React.createclass ({ Getinitialstate:function () {return {items:ListStore.getAll ()}; }, Componentdidmount:function () {Liststore.addchangelistener (this._onchange); }, Componentwillunmount:function () {Liststore.removechangelistener (this._onchange); }, _onchange:function () {this.setstate ({items:ListStore.getAll ()}); }, Createnewitem:function (event) {Buttonactions.addnewitem (' new item '); }, Render:function () {return <mybutton items={this.state.items} Onclick={this.createnewitem}/>; }});
In the above code, you can see that when Mybuttoncontroller discovers that the Store issues a Change event, it calls This._onchange to update the component state, triggering a re-render.
Components/mybutton.jsxvar React = require (' React '); var MyButton = function (props) { var items = props.items; var itemhtml = Items.map (function (ListItem, i) { return <li key={i}>{listitem}</li>; }); return <div> <ul>{itemHtml}</ul> <button onclick={props.onclick}>new item</ Button> </div>;}; Module.exports = MyButton;
Ix. Acknowledgements
This article was inspired by the article "Flux for Stupid People" by Andrew Ray.
Introduction to the Flux architecture tutorial