·3 min read·fluxLab.dev

React Performance Patterns We Use in Production

Practical React performance optimization techniques used across fluxLab.dev products, including code splitting, memoization, virtualization, and image optimization.

ReactPerformanceNext.jsFrontend

Introduction

Performance isn't an afterthought at fluxLab.dev — it's a feature. Across our products, we've developed patterns that keep React applications fast even as they grow in complexity. These are the techniques that made the biggest impact.

Pattern 1: Server Components by Default

In Next.js App Router, every component is a Server Component unless you add 'use client'. We lean into this aggressively.

The Rule

Only add 'use client' when you need:

  • Event handlers (onClick, onChange)
  • Browser APIs (localStorage, window)
  • React hooks (useState, useEffect)

In Jobber's frontend, 70% of components are Server Components. They add zero JavaScript to the client bundle.

Pattern 2: Lazy Load Below the Fold

Anything not visible on initial page load gets lazy loaded:

import dynamic from 'next/dynamic';

const Analytics = dynamic(() => import('./analytics'), {
  loading: () => <AnalyticsSkeleton />,
});

For Jobber's analytics dashboard, lazy loading the chart components reduced the initial bundle by 120KB. Users see the page layout instantly and charts load as they scroll.

Pattern 3: Optimize Images With Next/Image

Every image in our products uses next/image with proper configuration:

<Image
  src={screenshot.src}
  alt={screenshot.alt}
  fill
  sizes="(max-width: 768px) 100vw, (max-width: 1200px) 80vw, 1100px"
/>

The sizes attribute is critical — it tells the browser which image size to download based on viewport width. Without it, the browser downloads the largest image every time.

Pattern 4: Debounce Search and Filter Inputs

Real-time search is expensive. We debounce all search inputs by 300ms:

function useDebounce<T>(value: T, delay: number): T {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    const timer = setTimeout(() => setDebouncedValue(value), delay);
    return () => clearTimeout(timer);
  }, [value, delay]);

  return debouncedValue;
}

In Jobber's company list, this reduced API calls by 80% while keeping the interface responsive.

Pattern 5: Virtualize Long Lists

For lists with more than 50 items, we use virtualization. Only visible items render in the DOM. The Kanban board in Jobber uses this pattern — even with hundreds of application cards, scrolling stays smooth because only 10-15 cards are in the DOM at any time.

Pattern 6: Optimistic Updates for Drag-and-Drop

When a user drags an application card between columns in Jobber's Kanban board, we update the UI immediately — before the API call completes. If the API call fails, we revert the change and show an error.

This makes drag-and-drop feel instant, even though the backend update takes 50-100ms.

Pattern 7: Preload Critical Data

For pages users are likely to visit next, we preload data on hover:

<Link
  href={`/projects/${slug}`}
  onMouseEnter={() => prefetchProject(slug)}
>

This shaves 200-400ms off perceived navigation time because the data is already cached when the user clicks.

Pattern 8: Bundle Analysis

We run @next/bundle-analyzer on every release to catch bundle size regressions. Any increase over 10KB requires justification.

Common catches:

  • Importing an entire icon library instead of individual icons
  • Date libraries (moment.js → date-fns → native Intl)
  • Unused CSS from component libraries

Measuring Performance

We track Core Web Vitals in production:

  • LCP (Largest Contentful Paint): Target under 2.5s
  • FID (First Input Delay): Target under 100ms
  • CLS (Cumulative Layout Shift): Target under 0.1

Our portfolio site (flux-lab.dev) scores 95+ on Lighthouse for all metrics.

Conclusion

React performance optimization is about making smart choices consistently: Server Components over Client Components, lazy loading over eager loading, and measuring before optimizing. These patterns keep our products fast across all our production deployments.