Lazy routing

Earlier in the chapter, you learned how to split your route declarations by feature. This is done to avoid having a monolithic routes module, which can not only be difficult to decipher, but could also cause performance issues. Think about a large application that has dozens of features and hundreds of routes. Having to load all of these routes and components upfront would translate to a bad user experience.

In this final section of the chapter, we'll look at loading routes lazily. Part of this involves leveraging a loader such as Webpack, the loader used in this example. First, let's take a look at the main App component:

import React, { PropTypes } from 'react'; 
import { Link } from 'react-router'; 
 
// The "App" component is divided into 
// "header" and "content" sections, and will 
// simply render these properties. 
const App = ({ header, content }) => ( 
  <section> 
    <header> 
      {header} 
    </header> 
    <main> 
      {content} 
    </main> 
  </section> 
); 
 
// The "header" and "content" properties need to be 
// renderable values. 
App.propTypes = { 
  header: PropTypes.node.isRequired, 
  content: PropTypes.node.isRequired, 
}; 
 
// The default content for our "App" component. 
App.defaultProps = { 
  header: (<h1>App</h1>), 
  content: ( 
    <ul> 
      <li><Link to="users">Users</Link></li> 
      <li><Link to="groups">Groups</Link></li> 
    </ul> 
  ), 
}; 
 
export default App; 

This example application has two features: the brilliantly named users and groups. From the main page, there's a link to each feature. We know that this application will one day be successful and will grow to be huge. Therefore, we don't want to load all our routes and components up front, only when the user clicks one of these links.

Let's turn our attention to the main routes module now:

import React from 'react'; 
import { 
  Router, 
  browserHistory, 
} from 'react-router'; 
 
import App from './App'; 
 
// Defines the main application route as 
// a plain object, instead of a "<Route>" 
// component. 
const routes = { 
  // The "path" and "component" are specified, 
  // just like any other route. 
  path: '/', 
  component: App, 
 
  // This allows for lazy route configuration loading. 
  // The "require.ensure()" call allows for tools like 
  // Webpack to split the code bundles into separate 
  // modules that are loaded on demand. The actual 
  // "require()" calls get the route configurations. 
  // In this case, it's routes for the "users" feature 
  // and the "groups" feature. 
  getChildRoutes(partialNextState, callback) { 
    require.ensure([], (require) => { 
      const { users } = require('./users/routes'); 
      const { groups } = require('./groups/routes'); 
 
      callback(null, [ 
        users, 
        groups, 
      ]); 
    }); 
  }, 
}; 
 
// The "routes" object is passed to the "routes" 
// property. There are no nested "<Route>" elements 
// needed for this router. 
export default ( 
  <Router history={browserHistory} routes={routes} /> 
); 

The key aspect of the App route is the getChildRoutes() method. This is called when a route lookup needs to happen. This is perfect, because this allows the user to interact with the application without having to load these routes, until they click on one of the links. This is called lazy loading, because this code loads two other route modules.

The require.ensure() function is what enables code-splitting in code bundlers such as Webpack. Instead of creating one big bundle, the require.ensure() function tells the bundler that the require() calls inside this callback can go into a separate bundle that's loaded on demand. I recommend running this example within the code you've downloaded for this book and looking at the network developer tools as you navigate around the application.

Here's what the main page looks like when it's rendered:

Lazy routing

Now, let's take a look at one of the feature routes module:

import React from 'react'; 
 
import UsersHeader from './UsersHeader'; 
import UsersContent from './UsersContent'; 
 
// The route configuration for our "users" feature. 
export const users = { 
 
  // The components rendered by "App" are specified 
  // here as "UsersHeader" and "UsersContent". 
  path: 'users', 
  components: { 
    header: UsersHeader, 
    content: UsersContent, 
  }, 
  childRoutes: [ 
 
    // The "users/active" route lazily-loads the 
    // "UsersActiveHeader" and "UsersActiveContent" 
    // components when the route is activated. 
    { 
      path: 'active', 
      getComponents(next, cb) { 
        require.ensure([], (require) => { 
          const { 
            UsersActiveHeader, 
          } = require('./UsersActiveHeader'); 
 
          const { 
            UsersActiveContent, 
          } = require('./UsersActiveContent'); 
 
          cb(null, { 
            header: UsersActiveHeader, 
            content: UsersActiveContent, 
          }); 
        }); 
      }, 
    }, 
 
    // The "users/inactive" route lazily-loads the 
    // "UsersInactiveHeader" and "UsersInactiveContent" 
    // components when the route is activated. 
    { 
      path: 'inactive', 
      getComponents(next, cb) { 
        require.ensure([], (require) => { 
          const { 
            UsersInactiveHeader, 
          } = require('./UsersInactiveHeader'); 
 
          const { 
            UsersInactiveContent, 
          } = require('./UsersInactiveContent'); 
 
          cb(null, { 
            header: UsersInactiveHeader, 
            content: UsersInactiveContent, 
          }); 
        }); 
      }, 
    }, 
  ], 
}; 
 
export default users; 

It follows the same lazy loading principle as the main routes module. This time, it's the getComponents() method that is called when a matched route is found. The component code bundle is then loaded.

Here's what the Users page looks like:

Lazy routing

And here's what the Active Users page looks like:

Lazy routing

This technique is absolutely necessary for large applications. However, refactoring existing features to use this lazy loading approach to routing isn't too difficult. So, don't worry too much about lazy loading in the early days of your application.

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

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