≔ Menu

Pagination is a cornerstone of modern web development.

Whether you’re managing a sprawling e-commerce catalog or a simple list of blog posts, delivering data in bite-sized, navigable chunks is essential for both performance and user experience.

In this guide, we will build a robust, state-managed pagination component from scratch using HTML5, CSS3, and Vanilla JavaScript.

No frameworks, no libraries—just clean, performant code.


1. The Blueprint: Semantic HTML & Layout

A good component starts with a solid structure. We need a container for our items and a dedicated area for navigation controls.

<div class="pagination-container">
    <h3>Product Catalog</h3>
    <div id="item-list"></div>
    
    <div class="pagination-controls">
        <button id="prevBtn" aria-label="Previous Page">Prev</button>
        <div id="page-numbers"></div>
        <button id="nextBtn" aria-label="Next Page">Next</button>
    </div>
</div>

Key Detail: Notice the use of id attributes. These are our hooks for JavaScript, while the aria-label ensures our component remains accessible to screen readers.


2. Styling for Clarity (CSS)

Pagination should be intuitive. We use CSS to provide visual feedback, specifically focusing on the active and disabled states.

.pagination-controls {
    display: flex;
    gap: 8px;
    justify-content: center;
    align-items: center;
    margin-top: 20px;
}

button {
    padding: 8px 16px;
    border: 1px solid #007bff;
    background: #fff;
    color: #007bff;
    border-radius: 4px;
    transition: all 0.2s ease;
}

button.active {
    background: #007bff;
    color: #fff;
}

button:disabled {
    border-color: #ccc;
    color: #ccc;
    cursor: not-allowed;
}

3. The Logic Engine (JavaScript)

The “magic” of pagination happens in the logic of the slice. We treat our data as a single source of truth and use a mathematical window to view it.

A. Data and State

We define our dataset and a currentPage variable to track where the user is in the “stack.”

const data = Array.from({ length: 33 }, (_, i) => `Product Item #${i + 1}`);
const itemsPerPage = 5;
let currentPage = 1;

B. The Mathematical Window

To know which items to show, we calculate a start and end index. If we are on Page 3, and showing 5 items per page:

  • Start: (3 – 1) * 5 = 10

  • End: 10 + 5 = 15

  • Result: JavaScript slices indices 10 through 14.

function displayItems() {
    const listElement = document.getElementById('item-list');
    listElement.innerHTML = "";
    
    const start = (currentPage - 1) * itemsPerPage;
    const end = start + itemsPerPage;
    const paginatedData = data.slice(start, end);

    paginatedData.forEach(item => {
        const div = document.createElement('div');
        div.className = 'item-card';
        div.textContent = item;
        listElement.appendChild(div);
    });

    updateNavigationUI();
}

C. Dynamic Control Generation

We don’t want to hardcode page numbers. Instead, we calculate the totalPages by rounding up the data length divided by our limit ($33 / 5 = 6.6, which becomes 7 pages).

function setupPagination() {
    const pageNumbersElement = document.getElementById('page-numbers');
    pageNumbersElement.innerHTML = "";
    const totalPages = Math.ceil(data.length / itemsPerPage);

    for (let i = 1; i <= totalPages; i++) {
        const btn = document.createElement('button');
        btn.textContent = i;
        if (i === currentPage) btn.classList.add('active');
        
        btn.onclick = () => {
            currentPage = i;
            init(); // Re-render the UI
        };
        pageNumbersElement.appendChild(btn);
    }
}

4. Handling Edge Cases

A professional component handles user errors gracefully. We ensure the “Prev” and “Next” buttons are disabled when the user hits the boundaries of the data.

  • At Page 1: Disable “Prev”.

  • At Page 7 (Total): Disable “Next”.


Conclusion: Why This Matters

Building this from scratch teaches you the fundamentals of State Management.

By decoupling your data from your UI, you create a system that is easy to debug and modify.

Whether you’re building a large scale application or a simple portfolio, these core principles of data slicing and event handling are the building blocks of high-performance web applications.

Useful links below:

Let me & my team build you a money making website/blog for your businessĀ https://bit.ly/tnrwebsite_service

Get Bluehost hosting for as little as $1.99/month (save 75%)…https://bit.ly/3C1fZd2

Best email marketing automation solution on the market!Ā http://www.aweber.com/?373860

Build high converting sales funnels with a few simple clicks of your mouse!Ā https://bit.ly/484YV29

Join my Patreon for one-on-one coaching and help with your coding…https://www.patreon.com/c/TyronneRatcliff

Buy me a coffeeĀ ā˜•ļøhttps://buymeacoffee.com/tyronneratcliff

{ 0 comments }

In a React interview, there is one question that separates the juniors from the seniors: “How do you optimize a component that re-renders even when its props haven’t changed?”

React is fast by default, but as your application grows, “ghost” renders—renders that happen for no functional reason—can lead to a sluggish UI and a poor user experience.

Mastering these techniques isn’t just about passing an interview; it’s about building professional-grade software.


1. The Gatekeeper: React.memo

By default, when a parent component re-renders, all of its children re-render too.

React.memo is a Higher Order Component (HOC) that tells React to skip rendering a component if its props are the same as last time.

  • When to use it: For “Pure” components that render often with the same props.

  • The Interview Secret: Mention that React.memo only does a shallow comparison. If you pass a new object or array as a prop, the memoization will fail because the reference has changed.


2. Stabilizing Values with useMemo and useCallback

Since JavaScript treats objects and functions as unique references, you need a way to “lock” them so they don’t trigger re-renders in memoized children.

useMemo for Expensive Logic

Use this to cache the result of a calculation so it only runs when its dependencies change.

const filteredPosts = useMemo(() => {
  return posts.filter(post => post.title.includes(query));
}, [posts, query]); 

useCallback for Functions

Use this to cache a function definition. This is vital when passing a function to a child component wrapped in React.memo.

const handleSave = useCallback(() => {
  console.log("Saving post...");
}, []); // Empty array means the function reference stays the same forever

3. The “State Lift-Down” Pattern

Sometimes the best optimization is simply moving state closer to where it is used.

If a large parent component has state that only a tiny footer uses, moving that state into a Footer component prevents the entire page from re-rendering.

Pro-Tip: Before reaching for complex hooks, ask: “Can I move this state down a level?”


4. Leveraging the children Prop

This is a high-level composition trick. If you wrap a component around others using the children prop, React is smart enough to know the children haven’t changed even if the wrapper’s internal state does.

// The 'HeavyContent' won't re-render when 'count' changes
function LayoutWrapper({ children }) {
  const [count, setCount] = useState(0);
  return (
    <div onClick={() => setCount(c => c + 1)}>
      Clicked: {count}
      {children} 
    </div>
  );
}

Summary: When Not to Optimize

Optimization isn’t free. Every useMemo and useCallback adds a small memory overhead and a comparison step.

If you’re asked in an interview when to skip these: Explain that you shouldn’t optimize until you notice a performance bottleneck.

Over-memoizing a simple app can actually make it slower and harder to read.


Key Takeaways for your Portfolio:

  • Identify unnecessary renders using the React DevTools Profiler.

  • Stabilize references with useCallback and useMemo.

  • Refactor component architecture to keep state local.

Useful links below:

Let me & my team build you a money making website/blog for your businessĀ https://bit.ly/tnrwebsite_service

Get Bluehost hosting for as little as $1.99/month (save 75%)…https://bit.ly/3C1fZd2

Best email marketing automation solution on the market!Ā http://www.aweber.com/?373860

Build high converting sales funnels with a few simple clicks of your mouse!Ā https://bit.ly/484YV29

Join my Patreon for one-on-one coaching and help with your coding…https://www.patreon.com/c/TyronneRatcliff

Buy me a coffeeĀ ā˜•ļøhttps://buymeacoffee.com/tyronneratcliff

{ 0 comments }