Welcome to our most advanced installment yet! Today we’ll unlock professional-grade React techniques used in production apps at top companies.
Advanced Component Patterns
1. Compound Components
function Accordion({ children }) {
const [activeIndex, setActiveIndex] = useState(null);
return React.Children.map(children, (child, index) =>
React.cloneElement(child, {
isActive: index === activeIndex,
onToggle: () => setActiveIndex(index === activeIndex ? null : index)
})
);
}
function AccordionItem({ isActive, onToggle, children }) {
return (
<div className="accordion-item">
<button onClick={onToggle}>
{children[0]}
<span>{isActive ? '−' : '+'}</span>
</button>
{isActive && children[1]}
</div>
);
}
// Usage:
<Accordion>
<AccordionItem>
<h3>Section 1</h3>
<div>Content 1</div>
</AccordionItem>
<AccordionItem>
<h3>Section 2</h3>
<div>Content 2</div>
</AccordionItem>
</Accordion>
2. Render Props Pattern
function MouseTracker({ render }) {
const [position, setPosition] = useState({ x: 0, y: 0 });
const handleMouseMove = (e) => {
setPosition({ x: e.clientX, y: e.clientY });
};
return (
<div onMouseMove={handleMouseMove}>
{render(position)}
</div>
);
}
// Usage:
<MouseTracker
render={({ x, y }) => (
<div>
Mouse at: {x}, {y}
</div>
)}
/>
Performance Optimization
1. React.memo for Component Memoization
const ExpensiveComponent = React.memo(function ({ data }) {
// Heavy computations here
return <div>{processedData}</div>;
}, (prevProps, nextProps) => {
// Custom comparison (optional)
return prevProps.data.id === nextProps.data.id;
});
2. useMemo/useCallback Optimization
function ProductList({ products, searchTerm }) {
const filteredProducts = useMemo(() => {
return products.filter(product =>
product.name.toLowerCase().includes(searchTerm.toLowerCase())
);
}, [products, searchTerm]);
const handleAddToCart = useCallback((productId) => {
// Optimized callback
}, [cart]);
return (
<ul>
{filteredProducts.map(product => (
<ProductItem
key={product.id}
product={product}
onAddToCart={handleAddToCart}
/>
))}
</ul>
);
}
3. Virtualization for Large Lists
import { FixedSizeList } from 'react-window';
function BigList({ items }) {
return (
<FixedSizeList
height={500}
width={300}
itemSize={50}
itemCount={items.length}
>
{({ index, style }) => (
<div style={style}>
Item {items[index].id}
</div>
)}
</FixedSizeList>
);
}
Testing React Components
1. Jest + React Testing Library Setup
// Button.test.js
import { render, screen, fireEvent } from '@testing-library/react';
import Button from './Button';
test('handles clicks', () => {
const handleClick = jest.fn();
render(<Button onClick={handleClick}>Click me</Button>);
fireEvent.click(screen.getByText('Click me'));
expect(handleClick).toHaveBeenCalledTimes(1);
});
2. Testing Custom Hooks
import { renderHook, act } from '@testing-library/react-hooks';
import useCounter from './useCounter';
test('increments counter', () => {
const { result } = renderHook(() => useCounter());
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(1);
});
3. Integration Test Example
test('adds item to cart', async () => {
render(
<CartProvider>
<ProductList />
<Cart />
</CartProvider>
);
fireEvent.click(screen.getAllByText('Add to Cart')[0]);
expect(screen.getByText('1 items in cart')).toBeInTheDocument();
});
Practical Example: Optimized Data Table
function DataTable({ rows }) {
const [sortConfig, setSortConfig] = useState({ key: null, direction: 'asc' });
const sortedRows = useMemo(() => {
if (!sortConfig.key) return rows;
return [...rows].sort((a, b) => {
if (a[sortConfig.key] < b[sortConfig.key]) {
return sortConfig.direction === 'asc' ? -1 : 1;
}
if (a[sortConfig.key] > b[sortConfig.key]) {
return sortConfig.direction === 'asc' ? 1 : -1;
}
return 0;
});
}, [rows, sortConfig]);
const requestSort = (key) => {
setSortConfig(prev => ({
key,
direction: prev.key === key && prev.direction === 'asc' ? 'desc' : 'asc'
}));
};
return (
<table>
<thead>
<tr>
{columns.map(column => (
<th key={column.key} onClick={() => requestSort(column.key)}>
{column.label}
{sortConfig.key === column.key && (
sortConfig.direction === 'asc' ? ' ↑' : ' ↓'
)}
</th>
))}
</tr>
</thead>
<tbody>
{sortedRows.map(row => (
<TableRow key={row.id} row={row} />
))}
</tbody>
</table>
);
}
const TableRow = React.memo(function ({ row }) {
return (
<tr>
{columns.map(column => (
<td key={column.key}>{row[column.key]}</td>
))}
</tr>
);
});
What’s Next?
In our final installment, we’ll cover:
✅ State management with Redux Toolkit
✅ Server-side rendering with Next.js
✅ Deployment strategies for React apps
Exercise for You
Create an ImageLoader component that uses React.memo and implements intersection observer to lazy-load images only when they’re about to appear in the viewport.
Enjoyed this deep dive? Subscribe for our final part! 🎓
Questions? Let’s discuss in the comments!
Series Navigation:
🔹 Part 1: Introduction to React
🔹 Part 2: JSX, Components & Props
🔹 Part 3: State and Events
🔹 Part 4: useEffect & Conditional Rendering
🔹 Part 5: Custom Hooks & Context API
🔹 Part 6: Advanced Patterns & Optimization (You’re here)
🔹 Part 7: Redux & Next.js
