How to Build a High-Performance Tab Component in React

How to Build a High-Performance Tab Component in React

Creating a fast tab component in React means handling state well, reducing extra renders, and making tab content display quickly. Here's a simple example to help you begin:

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

const TabComponent = ({ tabs }) => {
  const [activeTab, setActiveTab] = useState(0);

  // Memoize the content for each tab to avoid unnecessary renders
  const tabContents = useMemo(() => {
    return tabs.map((tab, index) => (
      <div key={index} style={{ display: activeTab === index ? 'block' : 'none' }}>
        {tab.content}
      </div>
    ));
  }, [tabs, activeTab]);

  return (
    <div>
      <div style={{ marginBottom: '10px' }}>
        {/* Render the tab headers */}
        {tabs.map((tab, index) => (
          <button
            key={index}
            onClick={() => setActiveTab(index)}
            style={{
              marginRight: '10px',
              backgroundColor: activeTab === index ? '#007bff' : 'transparent',
              color: activeTab === index ? '#fff' : '#000',
              border: '1px solid #ccc',
              padding: '5px 10px',
              cursor: 'pointer',
            }}
          >
            {tab.label}
          </button>
        ))}
      </div>
      {/* Render the tab content */}
      {tabContents}
    </div>
  );
};

// Example usage
const App = () => {
  const tabs = [
    { label: 'Tab 1', content: 'Content for Tab 1' },
    { label: 'Tab 2', content: 'Content for Tab 2' },
    { label: 'Tab 3', content: 'Content for Tab 3' },
  ];

  return (
    <div>
      <h1>High-Performance Tab Component</h1>
      <TabComponent tabs={tabs} />
    </div>
  );
};

export default App;

In this example,

  • The activeTab state keeps track of the current tab.

  • useMemo is used to remember the content for each tab and prevent extra rendering.

  • Tab headers use buttons, and the active tab is emphasized.

  • Tab content shows up depending on which tab is active.

This is a simple example, and you can change it to fit your needs. If you have many tabs or more complicated content, think about using other improvements like lazy loading of content, virtualization, or a library like react-query to manage data fetching.

Real-time example of above using fetching data from API and displaying it in tab dynamically

Here, I'll use the JSONPlaceholder API to pretend we're fetching data.

import React, { useState, useEffect, useMemo } from 'react';

const TabComponent = ({ tabs }) => {
  const [activeTab, setActiveTab] = useState(0);
  const [tabData, setTabData] = useState([]);

  useEffect(() => {
    // Fetch data from an API (using JSONPlaceholder as an example)
    const fetchData = async () => {
      try {
        const response = await fetch('https://jsonplaceholder.typicode.com/posts');
        const data = await response.json();
        setTabData(data);
      } catch (error) {
        console.error('Error fetching data:', error);
      }
    };

    fetchData();
  }, []); // Run once when the component mounts

  // Memoize the content for each tab to avoid unnecessary renders
  const tabContents = useMemo(() => {
    return tabs.map((tab, index) => (
      <div key={index} style={{ display: activeTab === index ? 'block' : 'none' }}>
        {/* Display data for the selected tab */}
        {tabData
          .filter((dataItem) => dataItem.userId === index + 1)
          .map((filteredItem) => (
            <div key={filteredItem.id}>
              <h3>{filteredItem.title}</h3>
              <p>{filteredItem.body}</p>
            </div>
          ))}
      </div>
    ));
  }, [tabs, activeTab, tabData]);

  return (
    <div>
      <div style={{ marginBottom: '10px' }}>
        {/* Render the tab headers */}
        {tabs.map((tab, index) => (
          <button
            key={index}
            onClick={() => setActiveTab(index)}
            style={{
              marginRight: '10px',
              backgroundColor: activeTab === index ? '#007bff' : 'transparent',
              color: activeTab === index ? '#fff' : '#000',
              border: '1px solid #ccc',
              padding: '5px 10px',
              cursor: 'pointer',
            }}
          >
            {tab}
          </button>
        ))}
      </div>
      {/* Render the tab content */}
      {tabContents}
    </div>
  );
};

// Example usage
const App = () => {
  const tabs = ['User 1', 'User 2', 'User 3'];

  return (
    <div>
      <h1>Dynamic Tab Component with API Data</h1>
      <TabComponent tabs={tabs} />
    </div>
  );
};

export default App;

In this example,

  • In this example,

    • We get data from the JSONPlaceholder API when the component loads using useEffect.

    • We filter the data based on the chosen tab and show the right content in each tab.

    • The tab headers are fixed in this case, but you can change them based on the data you get.

Don't forget to change the API endpoint and data structure to match your real API information.