Before we start,
What is Single Responsibility Principle ?
It is an important principle in Computer Science Engineering. It means if you have a function or a class or any single identity of your code then it should have just a single responsibility. It is a good way to write code in modular fashion which makes it more reusable, maintainable and testable.
Need of Optimization
When we make our React app, we have several components in one React app (thousands of components in large scale apps), in that case having a different JavaScript file for each component would be a bad idea as we would not want our browser to keep sending network calls to load thousands of components, but with the help of bundlers, all the components are bundled in a single JavaScript file which is also not a good way as the size of the file might become big due to which browser can take time to load it which might slow down our app.
To solve these problems we break down our apps into several bundles or chunks of small sizes and they are loaded when they are to be used.
This process has several names like Chunking, Dynamic Bundling, Lazy Loading, Code Splitting, OnDemand Loading.
Dynamic Bundling
Dynamic Bundling is a technique used in web development to optimize the loading time and performance of web applications by breaking the application’s code into smaller chunks or bundles. These smaller bundles are then loaded only when they are needed, rather than all at once during the initial page load. This allows developers to serve only the necessary code for a specific part of the application, reducing the amount of unused code and improving performance, especially for large applications.
How it works ?
Code Splitting: Dynamic bundling typically involves code splitting, where the application code is divided into smaller files (bundles). These bundles are loaded dynamically based on user interaction or route navigation.
On-Demand Loading: When the user navigates to a specific route or triggers an action (like clicking a button), the browser loads the corresponding bundle only when required.
Libraries/Tools for Dynamic Bundling
Webpack: One of the most popular tools for bundling in modern web development. Webpack supports dynamic imports which can be used for code splitting.
React: React’s React.lazy and Suspense work together to enable dynamic bundling, particularly for route-based code splitting, so components are only loaded when they are rendered.
Parcel: A zero-configuration web application bundler that also supports automatic dynamic bundling.
Dynamic Bundling in React
In React, dynamic bundling can be easily achieved using lazy
and Suspense
. These two features allow React to lazy load components, meaning they are only loaded when the user needs them.
Lazy
The lazy
function helps you dynamically import components only when they are needed. Instead of loading the entire application at once, it allows React to load the component only when it’s about to be rendered.
import {lazy} from 'react';
const Component = lazy(() => import('./Component'));
Here, lazy
takes a function that imports a module. The component won’t be loaded until it is rendered in the DOM.
For example, if you have a large application and one of the components is only needed when a specific route is accessed (like a dashboard or user profile), you can use lazy
to load that component only when the user navigates to that route.
Suspense
When a component is being lazy-loaded, there’s a delay as the browser fetches the JavaScript file. This can create a moment where your UI might appear incomplete, causing a poor user experience and also might throw an error. To handle this, Suspense
is used to display a loading state while the lazy-loaded component is being fetched.
import {Suspense} from 'react';
<Suspense fallback={<div>Loading...</div>}>
<Component />
</Suspense>
The fallback
prop in Suspense
specifies what should be displayed while the component is being loaded. In the example above, it shows a simple “Loading…” message.
So, Suspense
is like a wrapper around the lazy-loaded component. It ensures that the user sees a fallback UI (like a spinner or loading text) until the component is fully loaded.
Best Practices for Dynamic Bundling in React
Route-Based Code Splitting: Lazy load components based on routes, so that only the components required for the current route are loaded.
Chunk Size: Try to keep the chunk sizes small to avoid long loading times for individual components.
User Interaction: If a component is shown after a user action (like opening a modal or clicking a button), lazy load it when the user interacts with the app.
This way, we can optimize our React app for faster and smoother UI which improves the user experience.