Chapter 10. Prepare Your React Application for Painless Maintenance with Flux

The reason why we decided to implement the Flux architecture in our React application is that we wanted to have a data flow that is easier to maintain. In the previous chapter, we implemented AppDispatcher, TweetActionCreators, and TweetStore. Let's quickly re-cap what they are used for:

  • TweetActionCreators creates and dispatches the actions
  • AppDispatcher dispatches all the actions to all stores
  • TweetStore stores and manages the application data

The only missing parts in our data flow are bits of functionality that are as follows:

  • Use TweetActionCreators to create the actions and start the data flowing
  • Use TweetStore to get data

Here are some important questions to ask: Where in our application does the data flow start? What is our data? If we answer these questions, we will understand where to start refactoring our application to adapt to the Flux architecture.

Snapterest allows users to receive and collect the latest tweets. The only data that our application is concerned with is tweets, so our data flow begins with receiving the new tweets. At the moment, what part of our application is responsible for receiving the new tweets? You might remember that our Stream component has the following componentDidMount() method:

componentDidMount: function () {
  SnapkiteStreamClient.initializeStream(this.handleNewTweet);
}

Yes, currently, we initiate a stream of new tweets after we render the Stream component. "Wait," you might say, "didn't we learn that React components should only be concerned with rendering the user interface?" You're correct. Unfortunately, at the moment, the Stream component is responsible for two different things:

  • Rendering the StreamTweet component
  • Initiating the data flow

Clearly, it will be a potential maintenance issue the in future. Let's decouple these two different concerns with the help of Flux.

Decoupling concerns with Flux

First, we'll create a new utility module called WebAPIUtils. Create WebAPIUtils.js in the ~/snapterest/source/utils/ directory:

var SnapkiteStreamClient = require('snapkite-stream-client'),
var TweetActionCreators = require('../actions/TweetActionCreators'),

function initializeStreamOfTweets() {    SnapkiteStreamClient.initializeStream(TweetActionCreators.receiveTweet);
}

module.exports = {
  initializeStreamOfTweets: initializeStreamOfTweets
};

In this utility module, we first import the SnapkiteStreamClient library and TweetActionCreators. Then, we create the initializeStreamOfTweets() function that initializes a stream of new tweets, just like in the componentDidMount() method of the Stream component, except with one key difference: whenever SnapkiteStreamClient receives a new tweet, it calls the TweetActionCreators.receiveTweet method that passes a new tweet to it as an argument:

SnapkiteStreamClient.initializeStream(TweetActionCreators.receiveTweet);

Remember that the TweetActionCreators.receiveTweet function expects to receive a tweet argument:

function receiveTweet(tweet) {
  // ... create and dispatch 'receive_tweet' action
}

This tweet will then be dispatched as a property of a new action object that the receiveTweet() function creates.

Then, the WebAPIUtils module exports our initializeStreamOfTweets() method:

module.exports = {
  initializeStreamOfTweets: initializeStreamOfTweets
};

Now we have a module with a method that initiates the data flow in our Flux architecture. Where should we import and call it? Since it's decoupled from the Stream component, and in fact, it doesn't depend on any React component at all, we can use it even before React renders anything. Let's use it in our app.js file:

var React = require('react'),
var ReactDOM = require('react-dom'),
var Application = require('./components/Application.react'),
var WebAPIUtils = require('./utils/WebAPIUtils'),

WebAPIUtils.initializeStreamOfTweets();

ReactDOM.render(<Application />, document.getElementById('react-application'));

As you can see, all that we need to do is import it and call the initializeStreamOfTweets() method:

var WebAPIUtils = require('./utils/WebAPIUtils'),

WebAPIUtils.initializeStreamOfTweets();

We do this before calling React's render() method:

ReactDOM.render(<Application />, document.getElementById('react-application'));

In fact, for the purpose of experimentation, you can remove the ReactDOM.render() line of code altogether and put a log statement in the TweetActionCreators.receiveTweet function. For example, run the following code:

function receiveTweet(tweet) {

  console.log("I've received a new tweet and now will dispatch it together with a new action.");

  var action = {
    type: 'receive_tweet',
    tweet: tweet
  };

  AppDispatcher.dispatch(action);
}

Don't forget to run the gulp command. Then, in your web browser, you will see the following output:

I am about to learn the essentials of React.js.

While on your web browser's console, you will see this output:

[Snapkite Stream Client] Socket connected
I've received a new tweet and now will dispatch it together with a new action.

This log message will be printed out for each new tweet that our application receives. Even though we didn't render any React component, our Flux architecture is still there:

  1. Our application receives a new tweet.
  2. It creates and dispatches a new action.
  3. No stores have registered with the dispatcher, so there is no one to receive the new action; hence, nothing is happening.

Now you can clearly see how React and Flux are two separate things that don't depend on each other at all.

We do want to render our React components. After all, we've put so much effort into creating them over the course of the last nine chapters! For this, we need to put our TweetStore into action. Can you tell where should we use it? We should use it in a React component that needs a tweet to render itself; our good old Stream component.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.16.111.9