React, from Facebook, is a very good class library for creating user interfaces. The only problem is that React doesn't focus on how your app handles data. Most people treat React as V in mv*. So, Facebook introduces a pattern called Flux that provides a functional channel that can be used for in-app data processing. This tutorial briefly introduces the Flux pattern and shows how to build a notepad application using the React and flux architectures.
Introduction to Flux
Flux relies on a single data stream. There are two key components in this Flux mode:
-
Stores : A store component that, as its name, stores data for this application.
-
actions : New data flows to stores through Actions. When the actions are called, Stores listens to the actions and makes some feedback (such as modifying the data). This guarantees the unidirectional nature of the data.
To reinforce this concept, let's make a real case. For example, in a Notepad application you might have the following arrangement:
-
A store called Notestore is used to store journal lists.
-
There is an action called Createnote. Notestore hears the action of CreateNode and then updates the list with a new journal when the action is invoked. Data can only be streamed to the store via action.
-
Notestore triggers an event every time the data changes. Your React component, if called nodelistcomponent, listens to this event and then updates the list of diaries that exist in the view layer. This is how the data flowing out of the store flows. So, the data flow can be visualized as follows:
The biggest advantage of Flux mode is that it ensures the smooth data in the application. For example, any change in data can only be made by action, which makes it easier to understand how to do this once the data changes affect the entire application.
Attention:
If you've seen Facebook's Guide to Flux, you'll certainly notice the concept of Dispatcher. Dispatcher is a callback function that is registered in the store. When the action is called, Dispatcher responds to it and sends the relevant data to all the registered store. The Store then checks the type of action and responds accordingly.
The above process is well simplified by a class library called reflux. It removes the concept of Dispatcher by enabling the actions to be monitored. So, in reflux, the store can listen to the action directly and respond to what they need.
To better understand the Flux pattern, we used reflux,react and node. js to create a Notepad app.
Build the development environment
We use React and reflux as Node modules and use Browserify to make them available on the client side as well. Here's how to build your environment:
-
We will use Browserify to package our React components, and the Actions and Stores are packaged as a client. js package.
-
We use grunt Watch to monitor the changes in the above components and rerun the browserify every time a change occurs.
-
Grunt Nodemon is used to restart the service whenever any. jsx or. js file changes, so you do not need to manually control it.
You can download the relevant code from GITHUB and open gruntfile.js to see the related tasks. When you have this library on your machine, you just need to run NPM install to have all of the node modules installed. Run the following command, and then start developing:
Grunt Watchgrunt Nodemon
This app can be accessed at localhost:8000 .
Use this app
We start with different components of this application. Here's how we split our UI into different components:
The following are the features of each component:
-
Noteapp: This is the root component, which contains two subcomponents: Notelistbox and Notecreationbox.
-
Notelistbox: There is a sub-component notelist. It will get a diary list from the Flux Store and pass them to notelist.
-
Notelist: Responsible for rendering each Note component. Pass a note object into each note component.
-
Note: Renders the specific content for a separate note item. In this example, only the title is shown. You can easily enter and show other details like Date,subtitle and so on.
-
Notecreationbox: This component renders a TextArea component, and if there is a journal ID that is currently being edited, it is passed to it.
-
TextArea: Provides a TextArea for user input. The text that passes the journal is saved in the Notecreationbox.
Create Actions
We use reflux to create an action. If you open actions/noteactions.js, you'll see how the action was created. Here is the code snippet:
var Reflux = require(‘reflux‘);var NoteActions = Reflux.createActions([ ‘createNote‘, ‘editNote‘]);module.exports = NoteActions;
Reflux.createactions is used to create an Action. We export these actions to make it easy to use them in the components.
Create Store
We created a store called Notestore to maintain the journal queue. The following code is used to create the store (stores/notestore.js):
var Reflux = require(‘reflux‘);var NoteActions = require(‘../actions/NoteActions‘);var _notes = []; //This is private notes arrayvar NoteStore = Reflux.createStore({ init: function() { // Here we listen to actions and register callbacks this.listenTo(NoteActions.createNote, this.onCreate); this.listenTo(NoteActions.editNote, this.onEdit); }, onCreate: function(note) { _notes.push(note); //create a new note // Trigger an event once done so that our components can update. Also pass the modified list of notes. this.trigger(_notes); }, onEdit: function(note) { // Update the particular note item with new text. for (var i = 0; i < _notes.length; i++) { if(_notes[i]._id === note._id) { _notes[i].text = note.text; this.trigger(_notes); break; } } }, //getter for notes getNotes: function() { return _notes; }, //getter for finding a single note by id getNote: function(id) { for (var i = 0; i < _notes.length; i++) { if(_notes[i]._id === id) { return _notes[i]; } } }});module.exports = NoteStore; //Finally, export the Store
As you can see, we listen to two action,createnote and Editnote, in the Init method. Similarly, we register a callback function when the action is invoked. The code to add/update a journal is simple. We lost the getter. Used to get a diary list. Finally, the store is leaking so that it can be used in our components.
Creating components
All of our React components are located in the React/components directory. I have shown all the structure of the UI. You can look at the source code of the download to learn more about each component. Here I show the most critical part (example: how our components invoke action and how to interact with the store)
Notelistbox:
This component obtains the journal list from Notestore, and spits them out to the Notelist component and renders the journal. This component looks like this:
|
varReact = require(‘react‘);varNoteList = require(‘./NoteList.jsx‘);varNoteStore = require(‘../../stores/NoteStore‘);varNoteListBox = React.createClass({ getInitialState: function() { return{ notes: NoteStore.getNotes() }; }, onChange: function(notes) { this.setState({ notes: notes }); }, componentDidMount: function() { this.unsubscribe = NoteStore.listen(this.onChange); }, componentWillUnmount: function() { this.unsubscribe(); }, render: function() { return( <div className="col-md-4"> <div className="centered"><a href=""onClick={this.onAdd}>Add New</a></div> <NoteList ref="noteList"notes={this.state.notes} onEdit={this.props.onEdit} /> </div> ); }});module.exports = NoteListBox; |
When this component starts to work, we can start listening for the Notestore change event. Whenever there is a change in this diary list, it will be broadcast. Our component listens to this event so that it can re-render the diary when there are any changes. The following line of code registers a listener:
This.unsubscribe = Notestore.listen (This.onchange);
Therefore, whenever a change occurs, the OnChange method of the component is called. This method receives an updated journal list and then changes the state.
|
this.setState({ notes: notes //state changes}); |
Since this.state.notes is passed into notelist as a prop, the notelist will re-render itself as long as the state has changed.
Finally, we added This.unsubscribe () in Componentwillunmount to remove the listener.
So that's why notelist is always up to date with the Change event on the Store. Now let's take a look at how a diary is created/edited.
Notecreationbox:
Take a closer look at the Notecreationbox method:
|
< Code class= "JS plain" >HANDLESAVE:&NBSP;function( Notetext, id) {&NBSP;&NBSP;if (ID) {&NBSP;&NBSP;&NBSP;&NBSP;noteactions.editnote ({ _id: id, text: notetext });&NBSP;&NBSP;}&NBSP;else {&NBSP;&NBSP;&NBSP;&NBSP;noteactions.createnote ({ _id: date.now (), text: notetext });&NBSP;&NBSP;}} |
This method will be called whenever the Save button is clicked. It accepts NoteText as its first parameter. If the ID is passed as the second argument, we know that this is an edit operation and call Noteactions.editnote (). Otherwise we will generate an ID for the new journal and call the Noteactions.createnote () method. Remember that Notestore listens for these actions. According to this action, the correct store callback is executed. Once the data has changed, store will trigger a change event and our Notelist component will update itself.
This is how data flows into the system and then flows through the Flux application.
Why use React on the service side
You may wonder why you use React and reflux on the server side. One of the coolest features of React is that it can be rendered on both the client and the server. Using this technique, you can create homogeneous applications that are rendered on the server side and behave like single-page applications. However, this is not necessary for a Notepad application, and you can easily use this scenario to create a complex isomorphic application.
Create a Notepad app with React and Flux