Skip to main content

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 labelLines or sizeInPx changes

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 transform and box-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:

ScenarioRender TimeMemory
Single disk3ms8KB
10 disks25ms80KB
100 disks240ms800KB
100 disks (virtualized)30ms100KB

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:

  1. Code split with React.lazy()
  2. Use virtualization for lists
  3. 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:

  1. Disable animations: animation={{ disableAnimations: true }}
  2. Reduce number of visible disks
  3. Use will-change: transform CSS 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:

  1. Use virtualization
  2. Implement cleanup in useEffect
  3. 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