React is a popular JavaScript library for building user interfaces, but with growing application sizes, the JavaScript bundle size can become large, leading to slow load times and poor performance. To mitigate this problem, React provides several code-splitting techniques that allow you to split your code into smaller chunks, reducing the initial JavaScript bundle's size and improving your application's performance.
In this blog post, we'll cover the following code-splitting techniques for React:
In React, there are many ways to split your code into smaller chunks and load them on demand. So we will cover the most popular ways of implementing code-splitting in React.
Dynamic imports allow you to split your code into smaller chunks and load them on demand, rather than loading everything at once. With dynamic imports, you can ensure that only the code required for a particular feature is loaded, leading to smaller initial JavaScript bundles and improved performance.
1import React, { useState, useEffect } from 'react';2
3const HomePage = () => {4 const [module, setModule] = useState(null);5
6 useEffect(() => {7 import('./HomePageWidget').then((mod) => setModule(mod.default));8 }, []);9
10 return module ? <module /> : <div>Loading...</div>;11};
React Lazy is a higher-order component that allows you to load components lazily, i.e., on-demand when they are needed. With React Lazy, you can ensure that your application only loads the elements it needs, reducing the size of the initial JavaScript bundle and improving performance.
1import React, { lazy, Suspense } from 'react';2
3const HomePage = lazy(() => import('./HomePage'));4
5const App = () => (6 <Suspense fallback={<div>Loading...</div>}>7 <HomePage />8 </Suspense>9);
Loadable Components is a higher-order component that allows you to split your code into smaller chunks and load them on demand, just like React Lazy. With Loadable Components, you can specify a loading component displayed while the code chunk is being loaded.
1import React from 'react';2import loadable from '@loadable/component';3
4const HomePage = loadable(() => import('./HomePage'), {5 fallback: <div>Loading...</div>,6});7
8const App = () => <HomePage />;
Now when we know some ways how to implement basic code-splitting, let's use them to create more advanced techniques.
Route-based code splitting is an optimisation technique that improves the performance of web applications by only loading the necessary code for a specific route. This can significantly reduce the amount of JavaScript that must be downloaded and parsed by the browser, leading to faster load times and improved overall user experience.
Another advantage of route-based code splitting is that it allows for better scalability as the application grows. With larger applications, the size of the JavaScript bundle can become unwieldy, leading to long load times and poor performance. By splitting the code into smaller chunks based on routes, developers can ensure that only the necessary code is loaded, improving performance even as the application grows.
1import React, { lazy, Suspense } from 'react';2
3const HomePage = lazy(() => import('./HomePage'));4const AboutPage = lazy(() => import('./AboutPage'));5
6function App() {7 return (8 <Suspense fallback={<div>Loading...</div>}>9 <Route exact path="/" component={HomePage} />10 <Route path="/about" component={AboutPage} />11 </Suspense>12 );13}
In this example, the HomePage
and AboutPage
components are loaded asynchronously using the lazy
function. The Suspense
component provides a fallback UI while the components are loaded. This allows the browser only to download and parse the code necessary for a specific route, improving the application's performance.
Preloading is a technique where you can load code chunks in the background while the user interacts with the application. This ensures that the code chunks are loaded before they are needed, reducing the time taken to load them and improving the overall performance of your application.
Here's an example of how you can use the React.lazy
function to implement preloading in React:
1import React, { lazy, Suspense } from 'react';2
3const LazyComponent = lazy(() => import('./LazyComponent'));4
5function App() {6 return (7 <>8 <Suspense fallback={<div>Loading...</div>}>9 <LazyComponent />10 </Suspense>11 </>12 );13}14
15export default App;
In the example above, the LazyComponent
is loaded lazily using the React.lazy
function. The Suspense
component is used to provide a fallback UI while the LazyComponent
is being loaded.
In this example, the LazyComponent
will be loaded in the background while the user interacts with the rest of your application. When the user navigates to the LazyComponent
, it will be loaded instantly, providing a smooth and seamless experience.
Inlining critical CSS involves including the styles required for the initial view of a page in the HTML file itself rather than loading them from a separate CSS file. This reduces the time taken to load the styles and improves the performance of your application.
Inlining critical CSS can have some advantages, but it also has some drawbacks. Some of the benefits include:
However, there are also some drawbacks to consider, such as:
Overall, inlining critical CSS can be a proper optimisation technique sometimes, but weighing the advantages and disadvantages before implementing it in your application is crucial.
Here's an example of how you can inline critical CSS in a React application using the styled-components library:
1import React from 'react';2import styled, { createGlobalStyle } from 'styled-components';3
4const GlobalStyle = createGlobalStyle`5 /* Your critical CSS rules */6 .header {7 background-color: blue;8 }9`;10
11const Header = styled.header`12 /* Your non-critical CSS rules */13 color: white;14 font-size: 20px;15`;16
17function App() {18 return (19 <>20 <GlobalStyle />21
22 <Header className="header">Welcome to my React App!</Header>23 </>24 );25}26
27export default App;
In this example, the critical CSS rules are defined in the GlobalStyle
component using the createGlobalStyle
method from the styled-components
library. These styles will be inlined in the HTML file and be available to the browser right away, without the need for an additional CSS file.
The Header
component uses the styled
method to define the non-critical CSS rules, which can be loaded later as a separate CSS file. This way, the critical styles are available for the initial view of the page, improving the performance, and the non-critical styles are loaded later, which won't affect the performance as much.
Dynamic chunks allow you to split your code into smaller, more manageable pieces that can be loaded on demand. This approach can significantly improve the performance of your application by reducing the amount of code that needs to be loaded and executed at once.
Dynamic chunks are similar to dynamic imports and React Lazy, but with an important difference. With dynamic chunks, you can specify the chunk name and the file name, giving you more control over the code-splitting process. This allows you to load only the code that is necessary for the current state of your application, improving the performance and reducing the amount of time it takes for your application to load.
By using dynamic chunks, you can also improve the organization of your codebase. By breaking down your code into smaller pieces, you can better manage the loading and execution of specific parts of your application. This can make it easier to maintain and debug your code, as well as make it more scalable for future development.
1// largeFile.js2export const ComponentA = React.lazy(() => import('./ComponentA'));3export const ComponentB = React.lazy(() => import('./ComponentB'));
1// index.js2import React, { lazy, Suspense } from 'react';3import { ComponentA, ComponentB } from './largeFile';4
5function App() {6 return (7 <>8 <Suspense fallback={<div>Loading...</div>}>9 <ComponentA />10 <ComponentB />11 </Suspense>12 </>13 );14}
With the above code, React will only load ComponentA
and ComponentB
when they are needed, rather than loading all of the components at once. This can significantly improve the performance of your application, as it reduces the amount of code that needs to be loaded and executed at once.
That's it; the post covers all the latest React code-splitting techniques and provides code examples to help you implement them in your React applications. With these techniques, you can ensure that your React applications are fast and performant, delivering a great user experience to your users.
Sign up to get updates when I write something new. No spam ever.
Subscribe to my Newsletter