I am building a Tabs component in React JS. I want to create a loop for my code, instead of hardcoding every tab(title, content). The code is working I need to simplify the code with a loop.
Tabs Component
import { useState } from "react"
import "./TabsStyles.css"
const Tabs = () => {
const [toggleTabsNumber, setToggleTabsNumber] = useState(null)
const togglerFunction = (index) => {
setToggleTabsNumber(index)
}
return (
<div>
<div className="c-tabs-main-container">
<div className="c-tabs-title-container">
<h3 onClick={() => togglerFunction(1)}>Tab 01</h3>
<h3 onClick={() => togglerFunction(2)}>Tab 02</h3>
<h3 onClick={() => togglerFunction(3)}>Tab 03</h3>
</div>
<div className="c-tabs-content-container">
<p className={toggleTabsNumber === 1 ? "c-active" : ""}>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ut similique asperiores nihil ullam non ad, dolorem quam eligendi rem praesentium nemo sed error pariatur voluptates hic voluptatem aliquam sapiente unde?</p>
<p className={toggleTabsNumber === 2 ? "c-active" : ""}>Qquam eligendi rem praesentium nemo sed error pariatur voluptates hic voluptatem aliquam sapiente unde?</p>
<p className={toggleTabsNumber === 3 ? "c-active" : ""}>PPhic voluptatem aliquam sapiente unde?</p>
</div>
</div>
</div>
)
}
export default Tabs
CodePudding user response:
You can modify Tabs Function component by passing tabs items as props; Then, loop them in your jsx.
const Tabs = ({ tabs }) => {
const [toggleTabsNumber, setToggleTabsNumber] = useState(null);
const togglerFunction = (index) => {
setToggleTabsNumber(index);
};
const isActiveTab = useCallback(
(tabId) => {
return toggleTabsNumber === tabId;
},
[toggleTabsNumber]
);
return (
<div className="c-tabs-main-container">
<div className="c-tabs-title-container">
{tabs.map((tab, indx) => (
<h3
key={`tab-title-${indx}-${tab.title}`}
onClick={() => {
togglerFunction(tab.id);
tab?.onClick?.();
}}
>
{tab.title}
</h3>
))}
</div>
<div className="c-tabs-content-container">
{tabs.map((tab, indx) => (
<p key={`tab-content-${indx}-${tab.content}`} className={isActiveTab(tab.id) ? 'c-active' : ''}>
{tab.content}
</p>
))}
</div>
</div>
);
};
tabs
is going to be array of tab which is something like
interface Tab {
id: string;
title: string;
content: string;
onClick?: function;
}
CodePudding user response:
How about something like this as a quick draft
import { useState } from "react"
import "./TabsStyles.css"
export const Tabs = (props) => {
const [activeTab, setActiveTab] = useState(0);
const tabs = React.Children.toArray(props.children)
.filter(child => React.isValidElement(child) && child.type === Tab);
return (
<div>
<div className="c-tabs-main-container">
<div className="c-tabs-title-container">
{
tabs.map((tab, index) => <h3 key={tab.key ?? index} onClick={() => setActiveTab(index)}>{
tab.title
}</h3>)
}
</div>
<div className="c-tabs-content-container">
{
tabs.map((tab, index) => <div key={tab.key ?? index} className={activeTab === index ? "c-active" : ""}>{
tab.children
}</div>)
}
</div>
</div>
</div>
)
}
// a vessel to collect the title and tab content as JSX and a marker to determine <Tab />s from possible garbage.
export const Tab = (props) => null;
which would then be used like this:
<Tabs>
<div> this will be ignored; only Tabs are rendered.</div>
<Tab title="Tab 01">
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ut similique asperiores nihil ullam non ad, dolorem quam eligendi rem praesentium nemo sed error pariatur voluptates hic voluptatem aliquam sapiente unde?
</Tab>
<Tab title="Tab 02">
Qquam eligendi rem praesentium nemo sed error pariatur voluptates hic voluptatem aliquam sapiente unde?
</Tab>
<Tab title="Tab 03">
PPhic voluptatem aliquam sapiente unde?
</Tab>
</Tabs>
this code may contain errors, I didn't test it, just typed it down quickly.