Performance
Tips for optimizing Retro Floppy performance and understanding its performance characteristics.
Performance Characteristics
Bundle Size
Minified:
- Component: ~15KB
- CSS: ~3KB
- Total: ~18KB
Gzipped:
- Component: ~5KB
- CSS: ~1KB
- Total: ~6KB
Tree-shaking: Fully supported with ES modules
Rendering Performance
Initial Render:
- Simple disk (no gradient): ~2-3ms
- With gradient: ~3-5ms
- With animations: +1-2ms
Re-render (memoized):
- No prop changes: ~0ms (skipped)
- Prop changes: ~2-3ms
Font Scaling Calculation:
- Per label line: ~1-2ms
- Runs only when
labelLinesorsizeInPxchanges
Gradient Generation:
- Color palette: ~0.05ms
- CSS gradient: ~0.01ms
- Text color calculation: ~0.1ms
- Total: ~0.17ms (memoized)
Memory Usage
Per Component Instance:
- DOM nodes: ~15-20 elements
- Memory: ~5-10KB
- Event listeners: 0-3 (if interactive)
100 Instances:
- Total memory: ~500KB-1MB
- Negligible impact on modern browsers
Animation Performance
CSS Transforms:
- GPU-accelerated
- 60 FPS on modern devices
- No layout reflow
Hover Effects:
- Transition duration: 300ms (default)
- Uses
transformandbox-shadow - Smooth on all devices
Optimization Tips
Memoization
The component is memoized with React.memo to prevent unnecessary re-renders.
Large Lists
When rendering many disks, use virtualization:
import { FixedSizeGrid } from 'react-window';
function VirtualizedGrid() {
return (
<FixedSizeGrid
columnCount={4}
columnWidth={150}
height={600}
rowCount={100}
rowHeight={150}
width={800}
>
{({ columnIndex, rowIndex, style }) => (
<div style={style}>
<FloppyDisk size="small" />
</div>
)}
</FixedSizeGrid>
);
}
Bundle Size
Retro Floppy is optimized for small bundle size:
- Tree-shakeable ES modules
- No external dependencies
- CSS Modules for scoped styles
Advanced Optimization Techniques
1. Lazy Loading
Load the component only when needed:
import { lazy, Suspense } from 'react';
const FloppyDisk = lazy(() => import('retro-floppy'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<FloppyDisk label={{ name: 'My Disk' }} />
</Suspense>
);
}
2. Debounce Prop Changes
Debounce frequent prop updates:
import { useMemo } from 'react';
import { debounce } from 'lodash';
function DiskWithSearch() {
const [search, setSearch] = useState('');
const debouncedSearch = useMemo(() => debounce(setSearch, 300), []);
return (
<>
<input onChange={(e) => debouncedSearch(e.target.value)} />
<FloppyDisk label={{ name: search }} />
</>
);
}
3. Intersection Observer
Render only visible disks:
import { useInView } from 'react-intersection-observer';
function LazyDisk({ label }) {
const { ref, inView } = useInView({
triggerOnce: true,
threshold: 0.1,
});
return (
<div ref={ref}>
{inView ? (
<FloppyDisk label={label} />
) : (
<div style={{ height: '200px' }} /> // Placeholder
)}
</div>
);
}
4. Disable Animations for Large Lists
Disable animations when rendering many disks:
<FloppyDisk
label={{ name: 'My Disk' }}
animation={{ disableAnimations: true }}
/>
5. Use Smaller Sizes
Smaller sizes render faster:
// Faster
<FloppyDisk size="small" />
// Slower
<FloppyDisk size="hero" />
6. Preload Gradients
For critical disks, preload gradients:
import { generateLabelGradient } from 'retro-floppy';
// Preload during app initialization
const gradientConfig = generateLabelGradient('My Disk', 'linear');
// Use later
<FloppyDisk label={{ name: 'My Disk' }} gradientOptions={gradientConfig} />;
Performance Monitoring
Measuring Render Time
Use React DevTools Profiler:
import { Profiler } from 'react';
function onRenderCallback(
id,
phase,
actualDuration,
baseDuration,
startTime,
commitTime,
) {
console.log(`${id} (${phase}) took ${actualDuration}ms`);
}
<Profiler id="FloppyDisk" onRender={onRenderCallback}>
<FloppyDisk label={{ name: 'My Disk' }} />
</Profiler>;
Bundle Size Analysis
Analyze bundle impact:
# Using webpack-bundle-analyzer
npm install --save-dev webpack-bundle-analyzer
# Add to webpack config
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin()
]
};
Performance Benchmarks
Test Setup:
- Device: MacBook Pro M1
- Browser: Chrome 120
- React: 18.2.0
Results:
| Scenario | Render Time | Memory |
|---|---|---|
| Single disk | 3ms | 8KB |
| 10 disks | 25ms | 80KB |
| 100 disks | 240ms | 800KB |
| 100 disks (virtualized) | 30ms | 100KB |
Recommendations:
- < 10 disks: No optimization needed
- 10-50 disks: Use React.memo
- 50-100 disks: Use virtualization
- 100+ disks: Use virtualization + lazy loading
Common Performance Issues
Issue 1: Slow Initial Render
Symptoms: First render takes >100ms
Causes:
- Large bundle size
- Too many disks rendered at once
- Complex gradients
Solutions:
- Code split with
React.lazy() - Use virtualization for lists
- Disable gradients if not needed
Issue 2: Laggy Animations
Symptoms: Animations stutter or drop frames
Causes:
- Too many animated disks
- Browser rendering bottleneck
- Low-end device
Solutions:
- Disable animations:
animation={{ disableAnimations: true }} - Reduce number of visible disks
- Use
will-change: transformCSS hint
Issue 3: High Memory Usage
Symptoms: Browser uses excessive memory
Causes:
- Rendering hundreds of disks
- Memory leaks in parent component
- Large images in labels
Solutions:
- Use virtualization
- Implement cleanup in
useEffect - Optimize label content
Best Practices
✅ Do
- Use virtualization for lists >50 items
- Memoize gradient options if custom
- Use predefined sizes when possible
- Disable animations for large lists
- Lazy load when not immediately visible
❌ Don't
- Render hundreds of disks without virtualization
- Change props on every frame
- Use very large custom sizes (>1000px)
- Nest FloppyDisk in expensive components
- Forget to memoize parent components
See Also
- Font Scaling Algorithm - Understanding scaling performance
- Gradient Generation Algorithm - Understanding gradient performance
- React Performance Optimization
- Web Performance