Lazy Loading
Lazy loading components based on stage transitions.
Overview
This example demonstrates how to use React's lazy loading with Stage Flow to improve performance by only loading components when they're needed.
Key Features to Observe
- Lazy Loading: Components are loaded only when needed
- Suspense Integration: Loading states during component loading
- Performance Optimization: Reduced initial bundle size
- Stage-Based Loading: Components load based on current stage
Live Example
Live Editor
// import React, { lazy, Suspense } from 'react'; // import { StageFlowEngine } from '@stage-flow/core'; // import { StageFlowProvider, useStageFlow, StageRenderer } from '@stage-flow/react'; function LazyLoadingExample() { // Create engine directly without useRef const engine = new StageFlowEngine({ initial: "login", stages: [ { name: "login", transitions: [{ target: "dashboard", event: "login" }], }, { name: "dashboard", transitions: [ { target: "profile", event: "navigateToProfile" }, { target: "settings", event: "navigateToSettings" }, { target: "login", event: "logout" }, ], }, { name: "profile", transitions: [ { target: "dashboard", event: "navigateToDashboard" }, { target: "settings", event: "navigateToSettings" }, { target: "login", event: "logout" }, ], }, { name: "settings", transitions: [ { target: "dashboard", event: "navigateToDashboard" }, { target: "profile", event: "navigateToProfile" }, { target: "login", event: "logout" }, ], }, ], }); engine.start(); // Lazy load components const LoginPage = React.lazy(() => Promise.resolve({ default: ({ data, send }) => ( <div style={{ padding: "20px", textAlign: "center" }}> <h3 style={{ color: "#333", margin: "0 0 15px 0" }}>Login Page</h3> <p style={{ color: "#666", margin: "0 0 20px 0" }}>This component is lazy loaded.</p> <button onClick={() => send("login")} style={{ padding: "10px 20px", backgroundColor: "#007bff", color: "white", border: "none", borderRadius: "4px", cursor: "pointer", }} > Login </button> </div> ), }) ); const DashboardPage = React.lazy(() => Promise.resolve({ default: ({ data, send }) => ( <div style={{ padding: "20px" }}> <h3 style={{ color: "#333", margin: "0 0 15px 0" }}>Dashboard</h3> <p style={{ color: "#666", margin: "0 0 20px 0" }}>This dashboard component is lazy loaded for better performance.</p> <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))", gap: "15px", marginTop: "20px", }} > <div style={{ padding: "15px", backgroundColor: "#f8f9fa", borderRadius: "4px", textAlign: "center", }} > <h4 style={{ color: "#333", margin: "0 0 10px 0" }}>Analytics</h4> <p style={{ color: "#666", margin: "0" }}>View your analytics data</p> </div> <div style={{ padding: "15px", backgroundColor: "#f8f9fa", borderRadius: "4px", textAlign: "center", }} > <h4 style={{ color: "#333", margin: "0 0 10px 0" }}>Reports</h4> <p style={{ color: "#666", margin: "0" }}>Generate reports</p> </div> </div> <div style={{ marginTop: "20px", display: "flex", gap: "10px" }}> <button onClick={() => send("navigateToProfile")} style={{ padding: "8px 16px", backgroundColor: "#007bff", color: "white", border: "none", borderRadius: "4px", cursor: "pointer", }} > Go to Profile </button> <button onClick={() => send("navigateToSettings")} style={{ padding: "8px 16px", backgroundColor: "#28a745", color: "white", border: "none", borderRadius: "4px", cursor: "pointer", }} > Go to Settings </button> </div> </div> ), }) ); const ProfilePage = React.lazy(() => Promise.resolve({ default: ({ data, send }) => ( <div style={{ padding: "20px" }}> <h3 style={{ color: "#333", margin: "0 0 15px 0" }}>Profile</h3> <p style={{ color: "#666", margin: "0 0 20px 0" }}>This profile component is lazy loaded.</p> <div style={{ padding: "15px", backgroundColor: "#f8f9fa", borderRadius: "4px", marginTop: "15px", }} > <h4 style={{ color: "#333", margin: "0 0 15px 0" }}>User Information</h4> <p style={{ color: "#666", margin: "0 0 8px 0" }}> <strong style={{ color: "#333" }}>Name:</strong> John Doe </p> <p style={{ color: "#666", margin: "0 0 8px 0" }}> <strong style={{ color: "#333" }}>Email:</strong> john@example.com </p> <p style={{ color: "#666", margin: "0" }}> <strong style={{ color: "#333" }}>Member since:</strong> January 2024 </p> </div> <div style={{ marginTop: "20px", display: "flex", gap: "10px" }}> <button onClick={() => send("navigateToDashboard")} style={{ padding: "8px 16px", backgroundColor: "#007bff", color: "white", border: "none", borderRadius: "4px", cursor: "pointer", }} > Back to Dashboard </button> <button onClick={() => send("navigateToSettings")} style={{ padding: "8px 16px", backgroundColor: "#28a745", color: "white", border: "none", borderRadius: "4px", cursor: "pointer", }} > Go to Settings </button> </div> </div> ), }) ); const SettingsPage = React.lazy(() => Promise.resolve({ default: ({ data, send }) => ( <div style={{ padding: "20px" }}> <h3 style={{ color: "#333", margin: "0 0 15px 0" }}>Settings</h3> <p style={{ color: "#666", margin: "0 0 20px 0" }}>This settings component is lazy loaded.</p> <div style={{ padding: "15px", backgroundColor: "#f8f9fa", borderRadius: "4px", marginTop: "15px", }} > <h4 style={{ color: "#333", margin: "0 0 15px 0" }}>Preferences</h4> <label style={{ display: "block", marginBottom: "10px", color: "#666" }}> <input type="checkbox" defaultChecked style={{ marginRight: "8px" }} /> Email notifications </label> <label style={{ display: "block", marginBottom: "10px", color: "#666" }}> <input type="checkbox" defaultChecked style={{ marginRight: "8px" }} /> Push notifications </label> <label style={{ display: "block", color: "#666" }}> <input type="checkbox" style={{ marginRight: "8px" }} /> SMS notifications </label> </div> <div style={{ marginTop: "20px", display: "flex", gap: "10px" }}> <button onClick={() => send("navigateToDashboard")} style={{ padding: "8px 16px", backgroundColor: "#007bff", color: "white", border: "none", borderRadius: "4px", cursor: "pointer", }} > Back to Dashboard </button> <button onClick={() => send("navigateToProfile")} style={{ padding: "8px 16px", backgroundColor: "#28a745", color: "white", border: "none", borderRadius: "4px", cursor: "pointer", }} > Go to Profile </button> </div> </div> ), }) ); return ( <StageFlowProvider engine={engine}> <div style={{ padding: "20px", border: "1px solid #ddd", borderRadius: "8px", maxWidth: "800px", backgroundColor: "white", }} > <h2 style={{ margin: "0 0 20px 0", color: "#333" }}> Lazy Loading Example </h2> <div style={{ padding: "20px", backgroundColor: "#f8f9fa", borderRadius: "4px", minHeight: "300px", }} > <React.Suspense fallback={ <div style={{ textAlign: "center", padding: "40px" }}> <div style={{ width: "40px", height: "40px", border: "4px solid #f3f3f3", borderTop: "4px solid #007bff", borderRadius: "50%", animation: "spin 1s linear infinite", margin: "0 auto", }} /> <p style={{ marginTop: "15px", color: "#666" }}> Loading component... </p> <style>{` @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } `}</style> </div> } > <StageRenderer stageComponents={{ login: LoginPage, dashboard: DashboardPage, profile: ProfilePage, settings: SettingsPage, }} /> </React.Suspense> </div> </div> </StageFlowProvider> ); }
Result
Loading...
Code Explanation
Engine Setup
The Stage Flow Engine is created directly:
const engine = new StageFlowEngine({
initial: "login",
stages: [...]
});
engine.start();
Lazy Loading Setup
Components are lazy loaded using React.lazy:
const LoginPage = React.lazy(() =>
Promise.resolve({
default: () => <LoginComponent />
})
);
Suspense Integration
Suspense provides a fallback during component loading:
<React.Suspense fallback={<LoadingSpinner />}>
{renderStage()}
</React.Suspense>
Stage-Based Rendering
Components are rendered using StageRenderer:
<StageRenderer
stageComponents={{
login: LoginPage,
dashboard: DashboardPage,
profile: ProfilePage,
settings: SettingsPage,
}}
/>
Benefits
- Reduced Initial Bundle Size: Only load components when needed
- Better Performance: Faster initial page load
- Memory Efficiency: Components are loaded on demand
- User Experience: Smooth loading states with Suspense
Related Examples
-
Performance Optimization - Using React.memo and useCallback
-
Basic Examples - Simple stage machine examples