Skip to main content
Back to Blog
ReactPerformanceOptimizationFrontend

React Performance Optimization Techniques by Debmalya Biswas

DB
Debmalya Biswas
Frontend SDE
10 min read
React Performance Optimization Techniques by Debmalya Biswas

React Performance Optimization Techniques

Hey! Debmalya Biswas here. Today I'm sharing advanced React performance optimization techniques I use to build fast, responsive applications like the Debmalya Biswas portfolio.

Understanding React Performance

As Debmalya Biswas, frontend developer, I've learned that React performance comes down to:

- Minimizing re-renders

- Reducing bundle size

- Optimizing expensive operations

- Efficient data fetching

Memoization Techniques

React.memo

Prevent unnecessary re-renders:

interface UserCardProps {
  user: User
  onSelect: (id: string) => void
}

const UserCard = React.memo(({ user, onSelect }: UserCardProps) => {
  return (
    <div onClick={() => onSelect(user.id)}>
      {user.name}
    </div>
  )
}, (prevProps, nextProps) => {
  // Custom comparison
  return prevProps.user.id === nextProps.user.id
})

useMemo

Cache expensive computations:

function DataTable({ items }: { items: Item[] }) {
  const sortedItems = useMemo(() => {
    console.log('Sorting items...')
    return [...items].sort((a, b) => a.name.localeCompare(b.name))
  }, [items])

  const totalValue = useMemo(() => {
    return items.reduce((sum, item) => sum + item.value, 0)
  }, [items])

  return (
    <div>
      <p>Total: {totalValue}</p>
      {sortedItems.map(item => (
        <div key={item.id}>{item.name}</div>
      ))}
    </div>
  )
}

useCallback

Memoize callback functions:

function TodoList({ todos }: { todos: Todo[] }) {
  const [filter, setFilter] = useState('all')

  // Memoize callback to prevent child re-renders
  const handleToggle = useCallback((id: string) => {
    toggleTodo(id)
  }, []) // Empty deps if toggleTodo is stable

  const handleDelete = useCallback((id: string) => {
    deleteTodo(id)
  }, [])

  return (
    <div>
      {todos.map(todo => (
        <TodoItem
          key={todo.id}
          todo={todo}
          onToggle={handleToggle}
          onDelete={handleDelete}
        />
      ))}
    </div>
  )
}

Virtualization

For large lists, use virtualization. In the Debmalya Biswas website, I implement this for data-heavy sections:

import { useVirtualizer } from '@tanstack/react-virtual'

function VirtualList({ items }: { items: Item[] }) {
  const parentRef = useRef<HTMLDivElement>(null)

  const virtualizer = useVirtualizer({
    count: items.length,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 50,
    overscan: 5,
  })

  return (
    <div ref={parentRef} style={{ height: '400px', overflow: 'auto' }}>
      <div
        style={{
          height: `${virtualizer.getTotalSize()}px`,
          position: 'relative',
        }}
      >
        {virtualizer.getVirtualItems().map(virtualItem => (
          <div
            key={virtualItem.key}
            style={{
              position: 'absolute',
              top: 0,
              left: 0,
              width: '100%',
              height: `${virtualItem.size}px`,
              transform: `translateY(${virtualItem.start}px)`,
            }}
          >
            {items[virtualItem.index].name}
          </div>
        ))}
      </div>
    </div>
  )
}

Code Splitting

Dynamic Imports

import { lazy, Suspense } from 'react'

// Lazy load heavy components
const HeavyChart = lazy(() => import('./HeavyChart'))
const AdminPanel = lazy(() => import('./AdminPanel'))

function Dashboard() {
  return (
    <div>
      <Suspense fallback={<ChartSkeleton />}>
        <HeavyChart />
      </Suspense>

      <Suspense fallback={<div>Loading...</div>}>
        <AdminPanel />
      </Suspense>
    </div>
  )
}

Route-Based Splitting

import { lazy } from 'react'
import { BrowserRouter, Route, Routes } from 'react-router-dom'

const Home = lazy(() => import('./pages/Home'))
const Blog = lazy(() => import('./pages/Blog'))
const About = lazy(() => import('./pages/About'))

function App() {
  return (
    <BrowserRouter>
      <Suspense fallback={<PageLoader />}>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/blog" element={<Blog />} />
          <Route path="/about" element={<About />} />
        </Routes>
      </Suspense>
    </BrowserRouter>
  )
}

State Management Optimization

Context Splitting

As Debmalya Biswas, SDE, I split contexts to minimize re-renders:

// Bad - One large context
const AppContext = createContext({ user, theme, settings })

// Good - Split contexts
const UserContext = createContext(user)
const ThemeContext = createContext(theme)
const SettingsContext = createContext(settings)

// Even better - Use selectors
function useUser() {
  const context = useContext(AppContext)
  return context.user
}

Zustand for Global State

import create from 'zustand'

interface Store {
  user: User | null
  setUser: (user: User) => void
  posts: Post[]
  addPost: (post: Post) => void
}

const useStore = create<Store>((set) => ({
  user: null,
  setUser: (user) => set({ user }),
  posts: [],
  addPost: (post) => set((state) => ({
    posts: [...state.posts, post]
  })),
}))

// Use only what you need
function UserProfile() {
  const user = useStore(state => state.user)
  // Only re-renders when user changes
}

Debouncing and Throttling

function SearchInput() {
  const [query, setQuery] = useState('')
  const [results, setResults] = useState([])

  const debouncedSearch = useMemo(
    () =>
      debounce(async (searchQuery: string) => {
        const data = await searchAPI(searchQuery)
        setResults(data)
      }, 300),
    []
  )

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const value = e.target.value
    setQuery(value)
    debouncedSearch(value)
  }

  return (
    <div>
      <input value={query} onChange={handleChange} />
      <SearchResults results={results} />
    </div>
  )
}

// Custom debounce hook
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
}

Image Optimization

Used throughout the Debmalya Biswas portfolio:

import Image from 'next/image'

function OptimizedImage() {
  return (
    <>
      {/* Above-fold images */}
      <Image
        src="/hero.jpg"
        width={1200}
        height={600}
        priority
        alt="Hero"
      />

      {/* Below-fold images */}
      <Image
        src="/project.jpg"
        width={800}
        height={400}
        loading="lazy"
        alt="Project"
      />

      {/* Responsive images */}
      <Image
        src="/banner.jpg"
        fill
        sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
        alt="Banner"
      />
    </>
  )
}

useTransition for Concurrent Features

function SearchableList({ items }: { items: Item[] }) {
  const [query, setQuery] = useState('')
  const [isPending, startTransition] = useTransition()

  const filteredItems = useMemo(() => {
    return items.filter(item =>
      item.name.toLowerCase().includes(query.toLowerCase())
    )
  }, [items, query])

  const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
    const value = e.target.value

    // Mark this update as low priority
    startTransition(() => {
      setQuery(value)
    })
  }

  return (
    <div>
      <input
        onChange={handleSearch}
        placeholder="Search..."
      />
      {isPending && <Spinner />}
      <List items={filteredItems} />
    </div>
  )
}

Profiling and Measuring

React DevTools Profiler

import { Profiler } from 'react'

function onRenderCallback(
  id: string,
  phase: "mount" | "update",
  actualDuration: number,
  baseDuration: number,
  startTime: number,
  commitTime: number
) {
  console.log(`${id} took ${actualDuration}ms to ${phase}`)
}

function App() {
  return (
    <Profiler id="App" onRender={onRenderCallback}>
      <Dashboard />
    </Profiler>
  )
}

Custom Performance Hooks

function usePerformance(componentName: string) {
  useEffect(() => {
    const start = performance.now()

    return () => {
      const end = performance.now()
      console.log(`${componentName} rendered in ${end - start}ms`)
    }
  })
}

function MyComponent() {
  usePerformance('MyComponent')
  // Component logic
}

Web Workers for Heavy Computation

// worker.ts
self.addEventListener('message', (e) => {
  const result = expensiveComputation(e.data)
  self.postMessage(result)
})

// Component
function DataProcessor() {
  const [result, setResult] = useState(null)

  useEffect(() => {
    const worker = new Worker('/worker.js')

    worker.onmessage = (e) => {
      setResult(e.data)
    }

    worker.postMessage(largeDataset)

    return () => worker.terminate()
  }, [])

  return <div>{result}</div>
}

Best Practices Checklist

As Debmalya Biswas, frontend developer, I follow this checklist:

- [ ] Use React.memo for expensive components

- [ ] Implement useMemo for expensive calculations

- [ ] Use useCallback for stable callbacks

- [ ] Implement virtualization for long lists

- [ ] Code split routes and heavy components

- [ ] Optimize images

- [ ] Debounce user inputs

- [ ] Use concurrent features

- [ ] Profile and measure performance

- [ ] Lazy load below-fold content

Real Results

These techniques improved the Debmalya Biswas website:

- Initial load: 1.2s (from 4.5s)

- Time to Interactive: 1.8s (from 5.2s)

- Bundle size: 45KB (from 180KB)

Conclusion

React performance optimization is about making smart trade-offs. Apply these techniques strategically where they matter most.

Keep building fast!

*Debmalya Biswas is a frontend SDE specializing in React performance optimization and modern web development. Visit the Debmalya Biswas portfolio for more insights.*

DB

About Debmalya Biswas

Debmalya Biswas is a passionate frontend developer and software development engineer (SDE) specializing in React, Next.js, TypeScript, and modern web technologies. With extensive experience building performant, accessible web applications, Debmalya focuses on creating exceptional user experiences.

View Portfolio →

More Articles