Web Development Insights & Tutorials

Explore articles, tutorials, and insights on modern web development, design trends, and programming best practices from my experience as a developer.

React Hooks Tutorial - Code Editor with React Code

Mastering React Hooks: A Comprehensive Guide for Developers

React Hooks have revolutionized how we write React components. In this comprehensive guide, I'll walk you through useState, useEffect, useContext, and custom hooks with practical examples that you can apply to your projects immediately.

Understanding React Hooks

React Hooks, introduced in React 16.8, allow you to use state and other React features without writing a class. They've become the standard way to write React components because they make code more reusable, readable, and testable.

useState: Managing Component State

The useState hook is the most fundamental hook. It lets you add React state to function components:

import React, { useState } from 'react';

function Counter() {
    const [count, setCount] = useState(0);
    
    return (
        <div>
            <p>You clicked {count} times</p>
            <button onClick={() => setCount(count + 1)}>
                Click me
            </button>
        </div>
    );
}

Best practices for useState:

  • Use multiple useState calls for unrelated state variables
  • Initialize with a function for expensive initial computations
  • Use functional updates when new state depends on previous state

useEffect: Handling Side Effects

The useEffect hook combines the functionality of componentDidMount, componentDidUpdate, and componentWillUnmount:

useEffect(() => {
    // This runs after every render
    document.title = `Count: ${count}`;
    
    // Cleanup function
    return () => {
        console.log('Component will unmount');
    };
}, [count]); // Only re-run if count changes

Custom Hooks: Reusable Logic

Create your own hooks to extract component logic into reusable functions:

function useLocalStorage(key, initialValue) {
    const [storedValue, setStoredValue] = useState(() => {
        try {
            const item = window.localStorage.getItem(key);
            return item ? JSON.parse(item) : initialValue;
        } catch (error) {
            return initialValue;
        }
    });
    
    const setValue = (value) => {
        try {
            const valueToStore = 
                value instanceof Function ? value(storedValue) : value;
            setStoredValue(valueToStore);
            window.localStorage.setItem(key, JSON.stringify(valueToStore));
        } catch (error) {
            console.log(error);
        }
    };
    
    return [storedValue, setValue];
}

By mastering these hooks, you can write cleaner, more maintainable React code that's easier to test and debug.

JavaScript Performance Optimization - Speedometer showing fast performance

JavaScript Performance Optimization: Techniques That Actually Work

Slow JavaScript can ruin user experience. In this article, I share practical techniques I've used to optimize JavaScript performance in production applications, from code splitting to efficient DOM manipulation and memory management.

Why JavaScript Performance Matters

With web applications becoming increasingly complex, JavaScript performance directly impacts user experience, conversion rates, and SEO rankings. Google's Core Web Vitals now include JavaScript execution time as a ranking factor.

1. Code Splitting and Lazy Loading

Modern bundlers like Webpack and tools like React.lazy() make code splitting straightforward:

// React.lazy for component-level splitting
const LazyComponent = React.lazy(() => import('./LazyComponent'));

function MyComponent() {
    return (
        <React.Suspense fallback={<div>Loading...</div>}>
            <LazyComponent />
        </React.Suspense>
    );
}

Dynamic imports for route-based splitting:

// Only load this module when needed
import('./module')
    .then(module => {
        module.init();
    })
    .catch(err => {
        console.error('Module loading failed:', err);
    });

2. Efficient DOM Manipulation

Minimize DOM operations and batch updates:

// Bad: Multiple reflows
for (let i = 0; i < 100; i++) {
    document.getElementById('list').innerHTML += `<li>Item ${i}</li>`;
}

// Good: Single reflow
let html = '';
for (let i = 0; i < 100; i++) {
    html += `<li>Item ${i}</li>`;
}
document.getElementById('list').innerHTML = html;

3. Memory Management

Prevent memory leaks by cleaning up event listeners and timeouts:

useEffect(() => {
    const handleResize = () => {
        // Handle resize
    };
    
    window.addEventListener('resize', handleResize);
    
    // Cleanup
    return () => {
        window.removeEventListener('resize', handleResize);
    };
}, []);

4. Debouncing and Throttling

Limit how often expensive functions can be called:

function debounce(func, wait) {
    let timeout;
    return function executedFunction(...args) {
        const later = () => {
            clearTimeout(timeout);
            func(...args);
        };
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
    };
}

// Usage
const handleSearch = debounce((query) => {
    // Perform search
}, 300);

5. Web Workers for Heavy Computation

Offload CPU-intensive tasks to background threads:

// main.js
const worker = new Worker('worker.js');
worker.postMessage({ data: largeDataSet });
worker.onmessage = (event) => {
    console.log('Result:', event.data);
};

// worker.js
self.onmessage = (event) => {
    const result = performHeavyCalculation(event.data);
    self.postMessage(result);
};

Implementing these techniques can improve your JavaScript performance by 50-70% in most applications.

CSS Grid vs Flexbox - CSS code comparison visualization

CSS Grid vs Flexbox: When to Use Each Layout System

Both CSS Grid and Flexbox are powerful layout tools, but they serve different purposes. I break down when to use each system with real-world examples to help you make better layout decisions in your projects.

Understanding the Fundamental Differences

CSS Grid is a two-dimensional layout system (rows AND columns), while Flexbox is a one-dimensional layout system (either rows OR columns). This fundamental difference determines when to use each.

When to Use CSS Grid

Use CSS Grid when you need control over both rows and columns:

.grid-container {
    display: grid;
    grid-template-columns: 1fr 2fr 1fr;
    grid-template-rows: 100px auto 100px;
    gap: 20px;
    grid-template-areas:
        "header header header"
        "sidebar main ads"
        "footer footer footer";
}

.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.ads { grid-area: ads; }
.footer { grid-area: footer; }

Perfect use cases for Grid:

  • Complete page layouts with header, footer, sidebar, and main content
  • Complex card layouts with overlapping elements
  • Image galleries with fixed row and column sizes
  • Forms with labels and inputs in a grid pattern

When to Use Flexbox

Use Flexbox for one-dimensional layouts and alignment:

.flex-container {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
}

.flex-item {
    flex: 1 0 200px; /* Grow, shrink, basis */
}

Perfect use cases for Flexbox:

  • Navigation bars and menus
  • Centering elements vertically and horizontally
  • Distributing space between items in a single row/column
  • Reordering items visually without changing HTML structure

Combining Grid and Flexbox

The real power comes from using both together:

.container {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 20px;
}

.card {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
}

.card-header {
    flex: 0 0 auto;
}

.card-content {
    flex: 1 1 auto;
}

.card-footer {
    flex: 0 0 auto;
}

Browser Support and Fallbacks

Both Grid and Flexbox have excellent browser support (over 95% globally). For older browsers:

@supports (display: grid) {
    .container {
        display: grid;
    }
}

@supports not (display: grid) {
    .container {
        display: flex;
        flex-wrap: wrap;
    }
}

Quick Decision Guide:

  • Grid: When you need to control layout in two dimensions
  • Flexbox: When you need to distribute space along a single axis
  • Both: When you need a grid of flex containers (most modern layouts)
Responsive Web Design - Multiple devices showing responsive layouts

Modern Responsive Design Techniques for 2023

Responsive design has evolved beyond simple media queries. Learn modern techniques like container queries, fluid typography, and responsive images that will make your websites work perfectly on any device.

The Evolution of Responsive Design

Responsive design is no longer just about mobile vs desktop. With devices ranging from smartwatches to 8K TVs, we need more sophisticated approaches.

1. Container Queries: The Game Changer

Container queries allow elements to adapt based on their container size, not just the viewport:

.component {
    container-type: inline-size;
    container-name: sidebar;
}

@container sidebar (min-width: 400px) {
    .component-content {
        display: grid;
        grid-template-columns: 1fr 1fr;
    }
}

2. Fluid Typography and Spacing

Use CSS clamp() for fluid values that scale between minimum and maximum sizes:

h1 {
    font-size: clamp(2rem, 5vw, 3.5rem);
    line-height: clamp(1.2, 1.1 + 0.2vw, 1.4);
}

.container {
    padding: clamp(1rem, 3vw, 3rem);
    gap: clamp(1rem, 2vw, 2rem);
}

3. Responsive Images with srcset and picture

Serve optimized images for different screen sizes and resolutions:

<img 
    src="image-800w.jpg"
    srcset="image-400w.jpg 400w,
            image-800w.jpg 800w,
            image-1200w.jpg 1200w"
    sizes="(max-width: 600px) 100vw,
           (max-width: 1200px) 50vw,
           800px"
    alt="Responsive image example"
>

<picture>
    <source media="(min-width: 1200px)" srcset="large.jpg">
    <source media="(min-width: 768px)" srcset="medium.jpg">
    <img src="small.jpg" alt="Responsive picture">
</picture>

4. CSS Grid for Intrinsic Responsiveness

Use auto-fit and minmax() for grids that adapt automatically:

.grid-container {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 1rem;
}

5. Mobile-First Media Queries

Always start with mobile styles and enhance for larger screens:

/* Base styles (mobile first) */
.component {
    padding: 1rem;
    font-size: 1rem;
}

/* Tablet and up */
@media (min-width: 768px) {
    .component {
        padding: 2rem;
        font-size: 1.1rem;
    }
}

/* Desktop and up */
@media (min-width: 1024px) {
    .component {
        padding: 3rem;
        font-size: 1.2rem;
    }
}

6. Performance Considerations

Responsive design affects performance. Optimize by:

  • Using CSS containment to limit reflows
  • Implementing lazy loading for below-the-fold content
  • Using intersection observer for animations
  • Testing with Chrome DevTools performance tab

Ready to Start Your Next Project?

I'm available for freelance work and would love to discuss how I can help bring your ideas to life. Let's create something amazing together.

Get In Touch