
Building High-Performance Web Applications
Essential techniques for optimizing web application performance and user experience.
Gyrate Digital
Author

Summary
Learn how to structure your React applications for maximum scalability and maintainability.
Building scalable React applications requires careful planning and adherence to best practices. As your application grows, maintaining code quality and performance becomes increasingly challenging. This comprehensive guide covers proven patterns and practices for building React applications that scale.
Before diving into code, establish a solid architectural foundation that supports growth.
src/
├── components/
│ ├── common/ # Shared components
│ ├── ui/ # Design system components
│ └── layout/ # Layout components
├── features/ # Feature-based organization
│ ├── auth/
│ │ ├── components/
│ │ ├── hooks/
│ │ ├── services/
│ │ └── types/
│ ├── dashboard/
│ └── products/
├── hooks/ # Custom hooks
├── services/ # API services
├── store/ # State management
├── types/ # TypeScript definitions
├── utils/ # Utility functions
└── constants/ # App constants
Separate business logic from presentation logic for better testability and reusability.
// Container Component (Business Logic)
import { useState, useEffect } from 'react';
import { UserList } from './UserList';
export const UserListContainer = () => {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchUsers = async () => {
try {
const response = await fetch('/api/users');
const data = await response.json();
setUsers(data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
fetchUsers();
}, []);
const handleUserDelete = async (userId) => {
try {
await fetch(`/api/users/${userId}`, { method: 'DELETE' });
setUsers(users.filter(user => user.id !== userId));
} catch (err) {
setError('Failed to delete user');
}
};
return (
<UserList
users={users}
loading={loading}
error={error}
onUserDelete={handleUserDelete}
/>
);
};
// Presentational Component (UI Only)
interface UserListProps {
users: User[];
loading: boolean;
error: string | null;
onUserDelete: (userId: string) => void;
}
export const UserList = ({ users, loading, error, onUserDelete }: UserListProps) => {
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return (
<ul>
{users.map(user => (
<li key={user.id}>
{user.name}
<button onClick={() => onUserDelete(user.id)}>Delete</button>
</li>
))}
</ul>
);
};
Create flexible, reusable component APIs that work together seamlessly.
import React, { createContext, useContext, useState } from 'react';
// Context for compound component communication
const TabsContext = createContext();
const Tabs = ({ children, defaultActive = 0 }) => {
const [activeIndex, setActiveIndex] = useState(defaultActive);
return (
<TabsContext.Provider value={{ activeIndex, setActiveIndex }}>
<div className="tabs">{children}</div>
</TabsContext.Provider>
);
};
const TabList = ({ children }) => (
<div className="tab-list">{children}</div>
);
const Tab = ({ index, children }) => {
const { activeIndex, setActiveIndex } = useContext(TabsContext);
return (
<button
className={`tab ${activeIndex === index ? 'active' : ''}`}
onClick={() => setActiveIndex(index)}
>
{children}
</button>
);
};
const TabPanels = ({ children }) => (
<div className="tab-panels">{children}</div>
);
const TabPanel = ({ index, children }) => {
const { activeIndex } = useContext(TabsContext);
return activeIndex === index ? (
<div className="tab-panel">{children}</div>
) : null;
};
// Usage
<Tabs>
<TabList>
<Tab index={0}>Profile</Tab>
<Tab index={1}>Settings</Tab>
<Tab index={2}>Notifications</Tab>
</TabList>
<TabPanels>
<TabPanel index={0}>Profile Content</TabPanel>
<TabPanel index={1}>Settings Content</TabPanel>
<TabPanel index={2}>Notifications Content</TabPanel>
</TabPanels>
</Tabs>
When to use: Component-specific state
Tools: useState, useReducer
Best for: Form inputs, UI state, simple interactions
When to use: App-wide state, complex interactions
Tools: Context API, Zustand, Redux Toolkit
Best for: User auth, app settings, complex workflows
When to use: API data, real-time updates
Tools: React Query, SWR, Apollo Client
Best for: API responses, caching, synchronization
// store/auth.ts
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
interface AuthState {
user: User | null;
isAuthenticated: boolean;
login: (user: User) => void;
logout: () => void;
}
export const useAuthStore = create<AuthState>()(
persist(
(set) => ({
user: null,
isAuthenticated: false,
login: (user) => set({ user, isAuthenticated: true }),
logout: () => set({ user: null, isAuthenticated: false }),
}),
{
name: 'auth-storage',
}
)
);
// store/products.ts
import { create } from 'zustand';
interface ProductState {
products: Product[];
loading: boolean;
error: string | null;
fetchProducts: () => Promise<void>;
addProduct: (product: Product) => void;
}
export const useProductStore = create<ProductState>((set, get) => ({
products: [],
loading: false,
error: null,
fetchProducts: async () => {
set({ loading: true, error: null });
try {
const response = await fetch('/api/products');
const products = await response.json();
set({ products, loading: false });
} catch (error) {
set({ error: error.message, loading: false });
}
},
addProduct: (product) =>
set((state) => ({
products: [...state.products, product],
})),
}));
// Route-based code splitting
import { lazy, Suspense } from 'react';
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Products = lazy(() => import('./pages/Products'));
const Analytics = lazy(() => import('./pages/Analytics'));
const App = () => (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/products" element={<Products />} />
<Route path="/analytics" element={<Analytics />} />
</Routes>
</Suspense>
</Router>
);
// Component-based code splitting
const HeavyComponent = lazy(() => import('./components/HeavyComponent'));
const MyComponent = () => {
const [showHeavy, setShowHeavy] = useState(false);
return (
<div>
<button onClick={() => setShowHeavy(true)}>
Load Heavy Component
</button>
{showHeavy && (
<Suspense fallback={<div>Loading heavy component...</div>}>
<HeavyComponent />
</Suspense>
)}
</div>
);
};
// Component memoization
const ProductCard = React.memo(({ product, onAddToCart }) => {
return (
<div className="product-card">
<h3>{product.name}</h3>
<p>${product.price}</p>
<button onClick={() => onAddToCart(product)}>Add to Cart</button>
</div>
);
});
// Callback memoization
const ProductList = ({ products, addToCart }) => {
const handleAddToCart = useCallback((product) => {
addToCart(product);
}, [addToCart]);
return (
<div>
{products.map(product => (
<ProductCard
key={product.id}
product={product}
onAddToCart={handleAddToCart}
/>
))}
</div>
);
};
// Value memoization
const UserProfile = ({ userId }) => {
const userData = useMemo(() => {
return expensiveUserLookup(userId);
}, [userId]);
const userStats = useMemo(() => {
return calculateUserStats(userData);
}, [userData]);
return (
<div>
<h2>{userData.name}</h2>
<p>Posts: {userStats.postCount}</p>
<p>Likes: {userStats.likeCount}</p>
</div>
);
};
import { FixedSizeList as List } from 'react-window';
const VirtualizedProductList = ({ products }) => {
const Row = ({ index, style }) => {
const product = products[index];
return (
<div style={style} className="product-row">
<img src={product.image} alt={product.name} />
<div>
<h4>{product.name}</h4>
<p>${product.price}</p>
</div>
<button>Add to Cart</button>
</div>
);
};
return (
<List
height={400}
itemCount={products.length}
itemSize={100}
width="100%"
>
{Row}
</List>
);
};
Create custom hooks to extract and reuse complex logic across components.
// hooks/useLocalStorage.ts
import { useState, useEffect } from 'react';
export function useLocalStorage<T>(key: string, initialValue: T) {
const [storedValue, setStoredValue] = useState<T>(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
return initialValue;
}
});
const setValue = (value: T | ((val: T) => T)) => {
try {
const valueToStore = value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
// Handle error silently
}
};
return [storedValue, setValue] as const;
}
// hooks/useApi.ts
import { useState, useCallback } from 'react';
export function useApi<T>(url: string) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const execute = useCallback(async (options?: RequestInit) => {
setLoading(true);
setError(null);
try {
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
setData(result);
return result;
} catch (err) {
const errorMessage = err instanceof Error ? err.message : 'An error occurred';
setError(errorMessage);
throw err;
} finally {
setLoading(false);
}
}, [url]);
return { data, loading, error, execute };
}
// Usage
const ProductManager = () => {
const [products, setProducts] = useLocalStorage('products', []);
const { data, loading, error, execute } = useApi('/api/products');
const addProduct = async (product) => {
try {
await execute({
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(product)
});
setProducts([...products, product]);
} catch (err) {
// Handle error silently
}
};
return (
<div>
{/* Component JSX */}
</div>
);
};
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { ProductCard } from './ProductCard';
const mockProduct = {
id: '1',
name: 'Test Product',
price: 29.99,
image: '/test-image.jpg'
};
const mockAddToCart = jest.fn();
describe('ProductCard', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('renders product information correctly', () => {
render(<ProductCard product={mockProduct} onAddToCart={mockAddToCart} />);
expect(screen.getByText('Test Product')).toBeInTheDocument();
expect(screen.getByText('$29.99')).toBeInTheDocument();
expect(screen.getByRole('button', { name: /add to cart/i })).toBeInTheDocument();
});
it('calls onAddToCart when button is clicked', () => {
render(<ProductCard product={mockProduct} onAddToCart={mockAddToCart} />);
const addButton = screen.getByRole('button', { name: /add to cart/i });
fireEvent.click(addButton);
expect(mockAddToCart).toHaveBeenCalledWith(mockProduct);
});
it('displays product image with correct alt text', () => {
render(<ProductCard product={mockProduct} onAddToCart={mockAddToCart} />);
const image = screen.getByAltText('Test Product');
expect(image).toBeInTheDocument();
expect(image).toHaveAttribute('src', '/test-image.jpg');
});
});
import { renderHook, act, waitFor } from '@testing-library/react';
import { useApi } from './useApi';
describe('useApi', () => {
beforeEach(() => {
global.fetch = jest.fn();
});
it('should handle successful API call', async () => {
const mockData = { id: 1, name: 'Test' };
(global.fetch as jest.Mock).mockResolvedValueOnce({
ok: true,
json: () => Promise.resolve(mockData),
});
const { result } = renderHook(() => useApi('/api/test'));
expect(result.current.loading).toBe(false);
expect(result.current.data).toBe(null);
act(() => {
result.current.execute();
});
expect(result.current.loading).toBe(true);
await waitFor(() => {
expect(result.current.loading).toBe(false);
expect(result.current.data).toEqual(mockData);
expect(result.current.error).toBe(null);
});
});
it('should handle API error', async () => {
const errorMessage = 'Network error';
(global.fetch as jest.Mock).mockRejectedValueOnce(new Error(errorMessage));
const { result } = renderHook(() => useApi('/api/test'));
act(() => {
result.current.execute();
});
await waitFor(() => {
expect(result.current.loading).toBe(false);
expect(result.current.data).toBe(null);
expect(result.current.error).toBe(errorMessage);
});
});
});
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null, errorInfo: null };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
this.setState({
error,
errorInfo
});
// Log error to monitoring service
logErrorToService(error, errorInfo);
}
render() {
if (this.state.hasError) {
return (
<div className="error-boundary">
<h2>Something went wrong.</h2>
<details style={{ whiteSpace: 'pre-wrap' }}>
{this.state.error && this.state.error.toString()}
<br />
{this.state.errorInfo.componentStack}
</details>
<button onClick={() => this.setState({ hasError: false })}>
Try again
</button>
</div>
);
}
return this.props.children;
}
}
// Usage
const App = () => (
<ErrorBoundary>
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/products" element={<Products />} />
</Routes>
</Router>
<ErrorBoundary>
);
Building scalable React applications is an ongoing process that requires attention to architecture, performance, and maintainability from day one. By following these patterns and best practices, you'll create applications that can grow with your business needs while maintaining code quality and developer productivity.
"Scalability isn't just about handling more users—it's about maintaining code quality, developer velocity, and user experience as your application grows. Invest in good architecture early, and your future self will thank you."
— Sarah Chen, Senior React Architect

Full-service digital agency specializing in design, development, and marketing that helps brands grow online.
33 Copgrove Road, Leeds,
West Yorkshire LS8 2SP, United Kingdom
+44 7943 939124
Office 210, Building 1691,
Road 432, Salmabad 704, Bahrain
+973 3467 9176
Subscribe to our newsletter for the latest updates.