{"id":283943,"date":"2019-03-06T17:07:28","date_gmt":"2019-03-07T00:07:28","guid":{"rendered":"http:\/\/css-tricks.com\/?p=283943"},"modified":"2019-03-06T17:07:28","modified_gmt":"2019-03-07T00:07:28","slug":"using-react-loadable-for-code-splitting-by-components-and-routes","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/using-react-loadable-for-code-splitting-by-components-and-routes\/","title":{"rendered":"Using React Loadable for Code Splitting by Components and Routes"},"content":{"rendered":"

In a bid to have web applications serve needs for different types of users, it\u2019s likely that more code is required than it would be for one type of user so the app can handle and adapt to different scenarios and use cases, which lead to new features and functionalities. When this happens, it\u2019s reasonable to expect the performance of an app to dwindle as the codebase grows.<\/p>\n

Code splitting is a technique where an application only loads the code it needs at the moment, and nothing more. For example, when a user navigates to a homepage, there is probably no need to load the code that powers a backend dashboard. With code splitting, we can ensure that the code for the homepage is the only code that loads, and that the cruft stays out for more optimal loading.<\/p>\n

Code splitting is possible in a React application using React Loadable<\/a>. It provides a higher-order component<\/a> that can be set up to dynamically import specific components at specific times.<\/p>\n

<\/p>\n

Component splitting<\/h3>\n

There are situations when we might want to conditionally render a component based on a user event, say when a user logs in to an account. A common way of handling this is to make use of state \u2014 the component gets rendered depending on the logged in state of the app. We call this component splitting<\/strong>.<\/p>\n

Let\u2019s see how that will look in code.<\/p>\n

\nSee the Pen
\nReact-Loadable<\/a> by Kingsley Silas Chijioke (
@kinsomicrote<\/a>)
\non
CodePen<\/a>.<\/span>\n<\/p>\n

As a basic example, say we want to conditionally render a component that contains an <h2><\/code> heading with \u201cHello.\u201d Like this:<\/p>\n

const Hello = () => {\r\n\treturn (\r\n\t\t<React.Fragment>\r\n\t\t\t<h2>Hello<\/h2>\r\n\t\t<\/React.Fragment>\r\n\t)\r\n}<\/code><\/pre>\n

We can have an openHello<\/code> state in the App component with an initial value of false<\/code>. Then we can have a button used to toggle the state, either display the component or hide it. We\u2019ll throw that into a handleHello<\/code> method, which looks like this:<\/p>\n

class App extends React.Component {\r\n\tstate = {\r\n\t\topenHello: false\r\n\t}\r\n\r\n\thandleHello = () => {\r\n\t\tthis.setState({ openHello: !this.state.openHello })\r\n\t}\r\n\trender() {\r\n\t\treturn (\r\n\t\t\t<div className=\"App\">\r\n\t\t\t\t<button onClick={this.handleHello}>\r\n\t\t\t\t\tToggle Component\r\n\t\t\t\t<\/button>\r\n\r\n\t\t\t\t{\r\n\t\t\t\t\tthis.state.openHello ?\r\n\t\t\t\t\t\t<Hello \/>\r\n\t\t\t\t\t: null\r\n\t\t\t\t}\r\n\t\t\t<\/div>\r\n\t\t);\r\n\t}\r\n}<\/code><\/pre>\n

Take a quick peek in DevTools and take note the Network tab:<\/p>\n

\"\"<\/figure>\n

Now, let\u2019s refactor to make use of LoadableHello. Instead of importing the component straight up, we will do the import using Loadable. We\u2019ll start by installing the react-loadable package:<\/p>\n

## yarn, npm or however you roll\r\nyarn add react-loadable<\/code><\/pre>\n

Now that\u2019s been added to our project, we need to import it into the app:<\/p>\n

import Loadable from 'react-loadable';<\/code><\/pre>\n

We\u2019ll use Loadable to create a \u201cloading\u201d component which will look like this:<\/p>\n

const LoadableHello = Loadable({\r\n\tloader: () => import('.\/Hello'),\r\n\tloading() {\r\n\t\treturn <div>Loading...<\/div>\r\n\t}\r\n})<\/code><\/pre>\n

We pass a function as a value to loader<\/code> which returns the Hello<\/code> component we created earlier, and we make use of import()<\/code> to dynamically import it. The fallback UI we want to render before the component is imported is returned by loading()<\/code>. In this example, we are returning a div<\/code> element, though we can also put a component in there instead if we want.<\/p>\n

Now, instead of inputting the Hello<\/code> component directly in the App<\/code> component, we\u2019ll put LoadableHello<\/code> to the task so that the conditional statement will look like this:<\/p>\n

{\r\n\tthis.state.openHello ?\r\n\t\t<LoadableHello \/>\r\n\t: null\r\n}<\/code><\/pre>\n

Check this out \u2014 now our Hello<\/code> component loads into the DOM only when the state is toggled by the button:<\/p>\n

\"\"<\/figure>\n

And that\u2019s component splitting: the ability to load one component to load another asynchronously!<\/p>\n

Route-based splitting<\/h3>\n

Alright, so we saw how Loadable can be used to load components via other components. Another way to go about it is us ing route-based splitting<\/strong>. The difference here is that components are loaded according to the current route.<\/p>\n

So, say a user is on the homepage of an app and clicks onto a Hello view with a route of \/hello<\/code>. The components that belong on that route would be the only ones that load. It\u2019s a fairly common way of handling splitting in many apps and generally works well, especially in less complex applications.<\/p>\n

Here\u2019s a basic example of defined routes in an app. In this case, we have two routes: (1) Home (\/<\/code>) and (2) Hello (\/hello<\/code>).<\/p>\n

class App extends Component {\r\n\trender() {\r\n\t\treturn (\r\n\t\t\t<div className=\"App\">\r\n\t\t\t\t<BrowserRouter>\r\n\t\t\t\t\t<div>\r\n\t\t\t\t\t\t<Link to=\"\/\">Home<\/Link>\r\n\t\t\t\t\t\t<Link to=\"\/hello\">Hello<\/Link>\r\n\t\t\t\t\t\t<Switch>\r\n\t\t\t\t\t\t\t<Route exact path=\"\/\" component={Home} \/>\r\n\t\t\t\t\t\t\t<Route path=\"\/hello\" component={Hello} \/>\r\n\t\t\t\t\t\t<\/Switch>\r\n\t\t\t\t\t<\/div>\r\n\t\t\t\t<\/BrowserRouter>\r\n\t\t\t<\/div>\r\n\t\t);\r\n\t}\r\n}<\/code><\/pre>\n

As it stands, all components will render when a use switches paths, even though we want to render the one Hello<\/code> component based on that path. Sure, it\u2019s not a huge deal if we\u2019re talking a few components, but it certainly could be as more components are added and the application grows in size.<\/p>\n

Using Loadable, we can import only the component we want by creating a loadable component for each:<\/p>\n

const LoadableHello = Loadable({\r\n\tloader: () => import('.\/Hello'),\r\n\tloading() {\r\n\t\treturn <div>Loading...<\/div>\r\n\t}\r\n})\r\nconst LoadableHome = Loadable({\r\n\tloader: () => import('.\/Home'),\r\n\tloading() {\r\n\t\treturn <div>Loading...<\/div>\r\n\t}\r\n})\r\nclass App extends Component {\r\n\trender() {\r\n\t\treturn (\r\n\t\t\t<div className=\"App\">\r\n\t\t\t\t<BrowserRouter>\r\n\t\t\t\t\t<div>\r\n\t\t\t\t\t\t<Link to=\"\/\">Home<\/Link>\r\n\t\t\t\t\t\t<Link to=\"\/hello\">Hello<\/Link>\r\n\t\t\t\t\t\t<Switch>\r\n\t\t\t\t\t\t\t<Route exact path=\"\/\" component={LoadableHome} \/>\r\n\t\t\t\t\t\t\t<Route path=\"\/hello\" component={LoadableHello} \/>\r\n\t\t\t\t\t\t<\/Switch>\r\n\t\t\t\t\t<\/div>\r\n\t\t\t\t<\/BrowserRouter>\r\n\t\t\t<\/div>\r\n\t\t);\r\n\t}\r\n}<\/code><\/pre>\n

Now, we serve the right code at the right time. Thanks, Loadable!<\/p>\n

What about errors and delays?<\/h3>\n

If the imported component will load fast, there is no need to flash a \u201cloading\u201d component. Thankfully, Loadable has the ability to delay the loading component from showing. This is helpful to prevent it from displaying too early where it feels silly and instead show it after a notable period of time has passed where we would expect to have seen it loaded.<\/p>\n

To do that, our sample Loadable component will look like this;<\/p>\n

const LoadableHello = Loadable({\r\n\tloader: () => import('.\/Hello'),\r\n\tloading: Loader,\r\n\tdelay: 300\r\n})<\/code><\/pre>\n

Here, we are passing the Hello<\/code> component as a value to loading<\/code>, which is imported via loader<\/code>. By default, delay<\/code> is set to 200ms, but we\u2019ve set ours a little later to 300ms.<\/p>\n

Now let\u2019s add a condition to the Loader<\/code> component that tells it to display the loader only after the 300ms delay we set has passed:<\/p>\n

const Loader = (props) => {\r\n\tif (props.pastDelay) {\r\n\t\treturn <h2>Loading...<\/h2>\r\n\t} else {\r\n\t\treturn null\r\n\t}\r\n}<\/code><\/pre>\n

So the Loader<\/code> component will only show if the Hello<\/code> component does not show after 300ms.<\/p>\n

react-loader also gives us an error<\/code> prop which we can use to return errors that are encountered. And, because it is a prop, we can let it spit out whatever we want.<\/p>\n

const Loader = (props) => {\r\n\tif (props.error) {\r\n\t\treturn <div>Oh no, something went wrong!<\/div>;\r\n\t} else if (props.delay) {\r\n\t\treturn <h2>Loading...<\/h2>\r\n\t} else {\r\n\t\treturn null;\r\n\t}\r\n}<\/code><\/pre>\n

Note that we\u2019re actually combining the delay and error handling together! If there\u2019s an error off the bat, we\u2019ll display some messaging. If there\u2019s no error, but 300ms have passed, then we\u2019ll show a loader. Otherwise, load up the Hello<\/code> component, please!<\/p>\n

That\u2019s a wrap<\/h3>\n

Isn\u2019t it great that we have more freedom and flexibility in how we load and display code these days? Code splitting \u2014 either by component or by route \u2014 is the sort of thing React was designed to do. React allows us to write modular components that contain isolated code and we can serve them whenever and wherever we want and allow them to interact with the DOM and other components. Very cool!<\/p>\n

Hopefully this gives you a good feel for code splitting as a concept. As you get your hands dirty and start using it, it\u2019s worth checking out more in-depth posts to get a deeper understanding of the concept.<\/p>\n