Sheetal Sindhu

Jul 13, 2025 • 5 min read

Algorithms Every Frontend Developer Should Know: Part II

The algorithms that actually matter in day-to-day development

Building on Part I's debouncing and throttling, here are the next essential algorithms I've used countless times in production applications. These solve real performance and user experience challenges you'll face daily.

3. Virtual Scrolling: Handle Massive Lists

The Problem: Rendering 10,000+ items crashes the browser and destroys performance.

The Solution:

import React, { useState, useEffect, useRef } from "react";

const VirtualScrollList = ({ items, itemHeight = 50, containerHeight = 400 }) => {
  const [scrollTop, setScrollTop] = useState(0);
  const [containerWidth, setContainerWidth] = useState(0);
  const containerRef = useRef(null);

  useEffect(() => {
    if (containerRef.current) {
      setContainerWidth(containerRef.current.offsetWidth);
    }
  }, []);

  const handleScroll = (e) => {
    setScrollTop(e.target.scrollTop);
  };

  // Calculate visible range
  const startIndex = Math.floor(scrollTop / itemHeight);
  const endIndex = Math.min(
    startIndex + Math.ceil(containerHeight / itemHeight) + 1,
    items.length
  );

  const visibleItems = items.slice(startIndex, endIndex);

  // Calculate total height and offset
  const totalHeight = items.length * itemHeight;
  const offsetY = startIndex * itemHeight;

  return (
    <div
      ref={containerRef}
      style={{
        height: containerHeight,
        overflow: "auto",
        border: "1px solid #ccc",
        position: "relative"
      }}
      onScroll={handleScroll}
    >
      <div style={{ height: totalHeight, position: "relative" }}>
        <div
          style={{
            transform: `translateY(${offsetY}px)`,
            position: "absolute",
            top: 0,
            left: 0,
            right: 0
          }}
        >
          {visibleItems.map((item, index) => (
            <div
              key={startIndex + index}
              style={{
                height: itemHeight,
                display: "flex",
                alignItems: "center",
                padding: "0 16px",
                borderBottom: "1px solid #eee",
                background: (startIndex + index) % 2 === 0 ? "#f9f9f9" : "#fff"
              }}
            >
              Row {startIndex + index + 1}: {item}
            </div>
          ))}
        </div>
      </div>
    </div>
  );
};

// Demo component
export default function App() {
  const [items] = useState(
    Array.from({ length: 100000 }, (_, i) => `Item ${i + 1}`)
  );

  return (
    <div style={{ padding: "2rem", fontFamily: "sans-serif" }}>
      <h2>Virtual Scrolling Demo</h2>
      <p>Smoothly scrolling through 100,000 items!</p>
      <VirtualScrollList items={items} itemHeight={50} containerHeight={400} />
    </div>
  );
}

Impact: Reduced memory usage by 95% and eliminated scroll lag in our data tables.

4. Smart Search with Fuzzy Matching

The Problem: Users make typos, and exact string matching fails to find relevant results.

The Solution:

import React, { useState, useMemo } from "react";

// Simple fuzzy search algorithm
const fuzzySearch = (query, items, threshold = 0.4) => {
  if (!query.trim()) return items;

  const calculateScore = (target, query) => {
    const targetLower = target.toLowerCase();
    const queryLower = query.toLowerCase();
    
    // Exact match gets highest score
    if (targetLower.includes(queryLower)) {
      return 1.0;
    }
    
    // Calculate character-by-character similarity
    let matches = 0;
    let queryIndex = 0;
    
    for (let i = 0; i < targetLower.length && queryIndex < queryLower.length; i++) {
      if (targetLower[i] === queryLower[queryIndex]) {
        matches++;
        queryIndex++;
      }
    }
    
    const score = matches / queryLower.length;
    return score;
  };

  return items
    .map(item => ({
      item,
      score: calculateScore(item.name, query)
    }))
    .filter(result => result.score >= threshold)
    .sort((a, b) => b.score - a.score)
    .map(result => result.item);
};

const SmartSearchDemo = () => {
  const [query, setQuery] = useState("");
  
  const sampleData = [
    { name: "JavaScript", category: "Programming" },
    { name: "TypeScript", category: "Programming" },
    { name: "React", category: "Framework" },
    { name: "Angular", category: "Framework" },
    { name: "Vue.js", category: "Framework" },
    { name: "Node.js", category: "Runtime" },
    { name: "Python", category: "Programming" },
    { name: "PostgreSQL", category: "Database" },
    { name: "MongoDB", category: "Database" },
    { name: "Redis", category: "Cache" }
  ];

  const filteredResults = useMemo(() => {
    return fuzzySearch(query, sampleData);
  }, [query]);

  return (
    <div style={{ padding: "2rem", fontFamily: "sans-serif" }}>
      <h2>Smart Fuzzy Search</h2>
      <input
        type="text"
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="Try 'javasript' or 'reactjs'..."
        style={{ 
          padding: "0.5rem", 
          width: "300px", 
          fontSize: "16px",
          marginBottom: "1rem"
        }}
      />
      <div>
        {filteredResults.length > 0 ? (
          filteredResults.map((item, idx) => (
            <div
              key={idx}
              style={{
                padding: "0.5rem",
                margin: "0.25rem 0",
                background: "#f0f0f0",
                borderRadius: "4px"
              }}
            >
              <strong>{item.name}</strong> - {item.category}
            </div>
          ))
        ) : (
          query && <p>No results found for "{query}"</p>
        )}
      </div>
    </div>
  );
};

export default SmartSearchDemo;

Impact: Improved search success rate by 60% in our product catalog.

5. Memoization: Cache Expensive Calculations

The Problem: Complex calculations run repeatedly with the same inputs, wasting CPU cycles.

The Solution:

import React, { useState, useMemo } from "react";

// Expensive calculation simulator
const expensiveCalculation = (number) => {
  console.log(`Computing fibonacci for ${number}...`);
  
  // Simulate expensive operation
  let result = 0;
  for (let i = 0; i < 1000000; i++) {
    result += Math.sqrt(i);
  }
  
  // Actual fibonacci calculation
  const fibonacci = (n) => {
    if (n <= 1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
  };
  
  return fibonacci(number);
};

// Memoization hook
const useMemoizedCalculation = (input) => {
  return useMemo(() => {
    return expensiveCalculation(input);
  }, [input]);
};

const MemoizationDemo = () => {
  const [number, setNumber] = useState(10);
  const [rerenderCounter, setRerenderCounter] = useState(0);
  
  // This will only recalculate when 'number' changes
  const result = useMemoizedCalculation(number);
  
  return (
    <div style={{ padding: "2rem", fontFamily: "sans-serif" }}>
      <h2>Memoization Demo</h2>
      <p>Open console to see caching in action!</p>
      
      <div style={{ marginBottom: "1rem" }}>
        <label>
          Number for calculation: 
          <input
            type="number"
            value={number}
            onChange={(e) => setNumber(parseInt(e.target.value) || 0)}
            min="0"
            max="35"
            style={{ marginLeft: "0.5rem", padding: "0.25rem" }}
          />
        </label>
      </div>
      
      <div style={{ marginBottom: "1rem" }}>
        <button 
          onClick={() => setRerenderCounter(c => c + 1)}
          style={{ padding: "0.5rem 1rem" }}
        >
          Force Re-render ({rerenderCounter})
        </button>
      </div>
      
      <div style={{ 
        padding: "1rem", 
        background: "#f0f0f0", 
        borderRadius: "4px" 
      }}>
        <strong>Result:</strong> {result}
      </div>
      
      <p style={{ color: "#666", fontSize: "14px" }}>
        The expensive calculation only runs when the number changes, 
        not on every re-render!
      </p>
    </div>
  );
};

export default MemoizationDemo;

Impact: Reduced calculation time by 80% in our dashboard analytics.

Key Takeaways

  • Virtual scrolling enables smooth handling of massive datasets

  • Fuzzy search improves user experience by handling typos and partial matches

  • Memoization prevents redundant expensive calculations

These algorithms solve real performance bottlenecks and are frequently tested in senior developer interviews. The key is understanding when to apply each pattern and measuring the actual performance gains.

Next Steps

Try the examples above, profile performance with Chrome DevTools, and implement these patterns in your current projects.

Pro tip: Always measure performance before and after implementing these algorithms to quantify the improvements.

Join Sheetal on Peerlist!

Join amazing folks like Sheetal and thousands of other builders on Peerlist.

peerlist.io/

It’s available... this username is available! 😃

Claim your username before it's too late!

This username is already taken, you’re a little late.😐

7

22

3