0
import { useState } from "react";

export default function TabsComponent() {
    const tabs = [
        { name: "Home", link: "#", content: "Home Content" },
        { name: "About", link: "#", content: "About Content" },
        { name: "Contact", link: "#", content: "Contact Content" },
    ];
    const [openTab, setOpenTab] = useState("Home");

    return (
        <div>
            <div className="container mx-auto">
                <div className="flex flex-col items-center justify-center max-w-xl">
                    <ul className="flex space-x-2">
                        {tabs.map((tab) => (
                            <li key={tab.name}>
                                <a
                                    href={tab.link}
                                    onClick={() => setOpenTab(tab.name)}
                                    className="inline-block px-4 py-2 text-gray-600 bg-white rounded shadow"
                                >
                                    {tab.name}
                                </a>
                            </li>
                        ))}
                    </ul>
                    <div className="p-3 mt-6 bg-white border">
                        {tabs.map((tab) => (
                            <div
                                key={tab.name}
                                className={
                                    tab.name === openTab ? "d-block" : "d-none"
                                }
                            >
                                {tab.content}
                            </div>
                        ))}
                    </div>
                </div>
            </div>
        </div>
    );
}

I'm new to React, I want this React Tabs functional component to be reusable. How to de-structure this entire component to use everywhere in the app.

I'm new to React, I want this React Tabs functional component to be reusable. How to de-structure this entire component to use everywhere in the app.

requirement

bv-dev
  • 3
  • 2
  • It depends _how_ reusable but the key thing would be for it to accept a tabs array in its props rather than defining them in the component itself. – Andy Dec 13 '22 at 13:06
  • You can pass the tabs as a property and initialise the internal openTab state based on the index of the property to be able to define which should be the default. This way the Tabs component will only care about render whatever structure you pass as a property. – leo Dec 13 '22 at 13:07
  • As above says -> `export default function TabsComponent({tabs}) { ..../*tabs is now a prop*/ } ` And to use -> `` – Keith Dec 13 '22 at 13:08
  • Can anyone show with the example? – bv-dev Dec 13 '22 at 13:11
  • @Keith It's not working, can you check once? – bv-dev Dec 13 '22 at 13:24

2 Answers2

0

What you did is great, just pass tabs as props

like this :

export default function TabsComponent({tabs}) {
 
  const [openTab, setOpenTab] = useState(tabs[0]);

  return (
    <div>
      <div className="container mx-auto">
        <div className="flex flex-col items-center justify-center max-w-xl">
          <ul className="flex space-x-2">
            {tabs.map((tab) => (
              <li key={tab.name}>
                <a
                  href={tab.link}
                  onClick={() => setOpenTab(tab.name)}
                  className="inline-block px-4 py-2 text-gray-600 bg-white rounded shadow"
                >
                  {tab.name}
                </a>
              </li>
            ))}
          </ul>
          <div className="p-3 mt-6 bg-white border">
            {tabs.map((tab) => (
              <div
                key={tab.name}
                className={
                  tab.name === openTab ? "d-block" : "d-none"
                }
              >
                {tab.content}
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

and in other component :

   <TabsComponent  tabs={[
        { name: "Home", link: "#", content: "Home Content" },
        { name: "About", link: "#", content: "About Content" },
        { name: "Contact", link: "#", content: "Contact Content" },
      ]} />

and if you want to have seperated component to handle them sepratly you can define each part as compnent

I did sth you can see here : https://codesandbox.io/s/material-ui-grid-demo-forked-ob4re4?file=/src/Tab.jsx

Ali Sattarzadeh
  • 3,220
  • 1
  • 6
  • 20
0

There are a couple of ways of doing this.

  1. Just create a prop called tabs, and you can then send the tabs array to the tabs prop.
export default function TabsComponent({tabs}) {
  //const tabs = ...  no need for this now..
  //rest of code the same
}

//call like
function Home() {
  return <TabsComponent tabs={[
    { name: "Home", link: "#", content: "Home Content" },
    { name: "About", link: "#", content: "About Content" },
    { name: "Contact", link: "#", content: "Contact Content" }
  ]}/>
}
  1. Another idea, is to actually use the implicit children prop.
export default function TabsComponent({children}) {
  //const tabs = ...  no need for this now..
  const tabs = children;
  //rest of code the same
}

//call like
function Home() {
  return <TabsComponent>
  {[
    { name: "Home", link: "#", content: "Home Content" },
    { name: "About", link: "#", content: "About Content" },
    { name: "Contact", link: "#", content: "Contact Content" }
  ]}
  </TabsComponent>;
}
  1. Another option is to actually compose your components, so you could have something like below, but there is a little bit more work required for handling state etc so not a trivial change, but for re-usability I believe is the nicest option. ->
function Home() {
  return <TabsComponent>
     <TabSection name="Home" link="#" default>
        Home Content
     </TabSection>
     <TabSection name="About" link="#">
        About Content
     </TabSection>
     <TabSection name="Contact" link="#">
        Contact Content
     </TabSection>
  </TabsComponent>;
}

I've not shown the code for option.3, as it's a tad more involved than just passing some props, but I think it's is the nicest option, so let us know if it's of interest.

Keith
  • 22,005
  • 2
  • 27
  • 44