TL;DR: React.lazy() and Suspense help you split your code into smaller chunks that load only when needed, improving your app's initial load time and performance.
React.lazy() enables you to render dynamic imports as regular components, while Suspense lets you specify loading states for lazy components. Together, they provide a powerful code-splitting solution that's built right into React.
First, let's create some components that we'll lazy load. Make sure each component has a default export.
// components/Dashboard.js
import React from 'react';
const Dashboard = () => {
return (
Dashboard
Welcome to your dashboard!
); }; export default Dashboard;
// components/Profile.js
import React from 'react';
const Profile = () => {
return (
User Profile
Manage your profile settings here.
); }; export default Profile;
Replace your regular imports with React.lazy() calls:
// App.js
import React, { Suspense, useState } from 'react';
// Lazy load components
const Dashboard = React.lazy(() => import('./components/Dashboard'));
const Profile = React.lazy(() => import('./components/Profile'));
Wrap your lazy components with Suspense and provide a fallback UI:
const App = () => {
const [currentView, setCurrentView] = useState('home');
const renderView = () => {
switch (currentView) {
case 'dashboard':
return (
Loading Dashboard...
}> ); case 'profile': return ( Loading Profile...}> ); default: return
Welcome to the Home Page!
; } }; return (
setCurrentView('home')}>HomesetCurrentView('dashboard')}>DashboardsetCurrentView('profile')}>Profile
{renderView()}
); }; export default App;
Handle loading errors gracefully by combining Suspense with Error Boundaries:
import React, { Suspense } from 'react';
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
render() {
if (this.state.hasError) {
return
Something went wrong while loading the component.
; } return this.props.children; } } const App = () => { return ( Loading...}> ); };
Create a reusable loading component for better UX:
// components/LoadingSpinner.js
const LoadingSpinner = ({ message = "Loading..." }) => (
{message}
); // Usage }>
Perfect for React Router applications:
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import React, { Suspense } from 'react';
const Home = React.lazy(() => import('./pages/Home'));
const About = React.lazy(() => import('./pages/About'));
const Contact = React.lazy(() => import('./pages/Contact'));
const App = () => (
Loading page...}>
} />
} />
} />
);
// Preload on hover for better UX
const handleMouseEnter = () => {
import('./components/HeavyComponent');
}; setShowComponent(true)}
onMouseEnter={handleMouseEnter}
>
Load Heavy Component
React Lazy and Suspense provide an elegant solution for code splitting without external dependencies. By implementing these patterns, you can significantly improve your app's initial load time and create a better user experience. Start with route-based splitting, then gradually apply it to other large components as needed.
Remember: The key is to find the right balance between too many small chunks (which can hurt performance) and too few large chunks (which defeat the purpose of code splitting).
Happy coding! 🚀
No comments yet
Be the first to comment on this post!