Home > Mobile >  Simple tabs component in ReactJS
Simple tabs component in ReactJS

Time:03-06

I am new to React.js, I know basic stuff like state, components, but I need to: Create a MyTabsComponent to be used like this:

<MyTabsComponent>
  <div title={"Section title 1"}>Content of section 1</div>
  <div title={"Section title 2"}>Content of section 2</div>
  <div title={"Section title 3"}>Content of section 2</div>
  <div title={"Section title 4"}>Content of section 2</div>
  <div title={"Section title 5"}>Content of section 2</div>
  
  .
  .
  .
  .
  .and so on..............
  .
  .
  .
  .
  .
  
</MyTabsComponent>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

See visual

The above code should render like this:

<div >
        <button >Section title 1</button>
        <button >Section title 2</button>
        <button >Section title 3</button>
        <button >Section title 4</button>
        <!--
        
        .
        .
        .
        .
        .
        .
        and so on..........
        -->
        
        <div >
            Content of section 1
        </div>
    </div>

What I've tried:

import React,{useState} from "react";

const MyTabsComponent = () => {
    const [title,setTitle] = useState(['Section 1','Section 2','Section 3']);
    const [ct,setCt] = useState(null);

    return (
        <div className="tabs">
        <TabButtons tabName={title} tabCt={setCt} />
        <div >
           Content : {ct}
             </div>
    </div>
    );
};

const TabButtons = (props) => {
    return (
          <>
          {
              props.tabName.map((item,i)=>
              <button onClick={()=>props.tabCt(i)} className="btn">{item}</button>

              ) 
          }
            
            </>
    );
};

export default MyTabsComponent;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

I don't know how to do this for any number of tabs. Rest I can handle-- CSS, onClick events I understand well, as I know JS well.

EDIT: I found an article on Compound Components https://blog.logrocket.com/understanding-react-compound-components/

and they say:

import React, { useState, createContext, useContext } from "react";

//the name of this context will be DataContext
const DataContext = createContext({});

function Tab({ id, children }) {
  //extract the 'setActiveTabID` method from the DataContext state.
  const [, setActiveTabID] = useContext(DataContext);
  return (
    <div>
      <div onClick={() => setActiveTabID(id)}>{children}</div>
    </div>
  );
}
function TabPanel({ whenActive, children }) {
  //get the 'activeTabID' state from DataContext.
  const [activeTabID] = useContext(DataContext);
  return <div>{activeTabID === whenActive ? children : null}</div>;
}

function TabSwitcher(props) {
  const [activeTabID, setActiveTabID] = useState("a");
  //since this component will provide data to the child components, we will use DataContext.Provider
  return (
    <DataContext.Provider value={[activeTabID, setActiveTabID]}>
      {props.children}
    </DataContext.Provider>
  );
}

export default TabSwitcher;
export { Tab, TabPanel };

And to use:

import TabSwitcher, { Tab, TabPanel } from "./TabSwitcher";

function App() {
  return (
    <div className="App">
      <h1>TabSwitcher with Compound Components</h1>
      <TabSwitcher>
        <Tab id="a">
          <button>a</button>
        </Tab>
        <Tab id="b">
          <button>b</button>
        </Tab>

        <TabPanel whenActive="a">
          <div>a panel</div>
        </TabPanel>

        <TabPanel whenActive="b">
          <div>b panel</div>
        </TabPanel>
      </TabSwitcher>
    </div>
  );
}
export default App;

The problem is: they are using

TabPanel

as a container whereas I want a <div>

CodePudding user response:

The problem is: they are using TabPanel as a container whereas I want a

When you say "I want a <div>", do you mean that you want to write div in your code, or that you want a div in the DOM?

The example you found, where they use TabPanel, does render a div to the DOM, because TabPanel returns a div.

One thing that jumps out is you don't need to store your Titles in state, because they are never changing.

To do what you're trying to do, I'd probably go like this:

import React,{useState} from "react";

const tabData = [
  {title: "Section title 1", content: "Content of section 1"}
  {title: "Section title 2", content: "Content of section 2"}
  {title: "Section title 3", content: "Content of section 3"}
]

const MyTabsComponent = () => {
    const [ct,setCt] = useState(null);

    return (
        <div className="tabs">
         {tabData.map(({title}, i) => (
           <TabButton
              title={title}
              isActive={i === ct}
              onClick={()=>props.tabCt(i)} />
         )}       
          <div >
           Content : {tabData[ct].content}
          </div>
        </div>
    );
};

const TabButton = ({ title, isActive, onClick }) => {
    return (
            <button onClick={onClick} className={isActive ? "active-btn" : "btn"}>
              {title}
            </button>
    );
};

export default MyTabsComponent;

CodePudding user response:

From what I can tell, your question is how to render any number of tabs? It seems that your snippet already does this. However, you did have one too many parenthesis, or one too few depending on how you look at it.

import React,{useState} from "react";

const myTabs = ['Section 1','Section 2','Section 3'];

const MyTabsComponent = () => {
    const [ct,setCt] = useState(null);

    return (
      <div className="tabs">
        <TabButtons tabCt={setCt} />
        <div>Content: {ct}</div>
      </div>
    );
};

const TabButtons = (props) => {
    return (
      <>
      {myTabs.map((item,i) => (
        <button onClick={()=>props.tabCt(i)} className="btn">
          {item}
        </button>
      )}
      </>
    );
};

export default MyTabsComponent;

This should work. You could have 1 or 1000 tabs in myTabs and it would render all of them.

  • Related