简体   繁体   中英

How to "override" react-bootstrap tab component

I have a little problem. I understand it, but don't know how to build a correct implementation...

I have a form with Tabs / Tab components, to display content.

At start, I used this kind of syntax:

<Tabs
        id="profile-page-tabs"
        activeKey={active_tab}
        onSelect={(t) => toggle(t)}
        className="mb-3">
    <Tab 
            tabAttrs={ title: t("Profile-Title") }
            eventKey="mykey"
            title={<span>{<AccountIcon />}{" "}<span className="d-none d-md-inline">{t("Profile-Title")}</span></span>}>
        <h2 className="d-block d-md-none">{t("Profile-Title"}</h2>
        <ProfileForm currentUser={currentUser} />
</Tabs>

And it work as expected.

Now, I would like to refactor this logic to have a Component that return all tabs with same "configuration" (classes, h2, ...) to allow possibility to change the classes in only one place.

My first try was with a function:

import { Tab } from "react-bootstrap";

export function buildTab(icon, eventKey, children, label, title = null) {
    if (!title) {
        title = label;
    }

    return (
        <Tab
                tabAttrs={{ title: title }}
                eventKey={eventKey}
                title={<span>{icon}{" "}<span className="d-none d-md-inline">{label}</span></span>}>
            <h2 className="d-block d-md-none">{label}</h2>
            {children}
        </Tab>
    )
}

And another time, it work like a charm. But with this implementation, I must call my tabs like that:

<Tabs
        id="profile-page-tabs"
        activeKey={active_tab}
        onSelect={(t) => toggle(t)}
        className="mb-3">
    {buildTab(
            <Person />,
            'mykey',
            <ProfileForm currentUser={currentUser} />,
            t('Profile-Title')
    )}
</Tabs>

So working, but not really nice... I created a component like this to call it "like a component":

import { Tab } from "react-bootstrap";

const TabItem = ({title, eventKey, icon, titleAttr, children}) => {

    if (!titleAttr) {
        titleAttr = title;
    }
    return(
        <Tab
                tabAttrs={{ title: titleAttr }}
                eventKey={eventKey}
                title={<span>{icon}{" "}<span className="d-none d-md-inline">{title}</span></span>}>
            <h2 className="d-block d-md-none">{title}</h2>
            {children}
        </Tab>
    );
}
export default TabItem;

And I call it like that:

<Tabs
        id="profile-page-tabs"
        activeKey={active_tab}
        onSelect={(t) => toggle(t)}
        className="mb-3">
    <TabItem
            icon={<Person />}
            eventKey='mykey',
            title={t('Profile-Title')}
        <ProfileForm currentUser={currentUser} />
    </TabItem>
</Tabs>

Problem is in this case, the react-bootstrap Tabs component doesn't use my component... It simply build a Tab component with properties it found into my declaration...

So I ask myself if it's possible to do things like that, or the "function" implementation is the best way to achieve my goal...

Thanks in advance for any suggestion.

This is indeed a really weird implementation in react-bootstrap. I also came across this. I would even call it "bug", because I don't see any reason why Tabs component should be implemented in such way.

Your only bet at the moment is to work with map, for example:

  { tabsConfiguration.map(tabConfig => {
    return (
      <Tab
          someAttr={tabConfig.someAttr}>
        <h2 className="d-block d-md-none">{tabConfig.title}</h2>
        {tabConfig.body}
    </Tab>
    )
    })}

Maybe we should open an issue in react-bootstrap project, if I'm not the only one wondering about this unexpected behaviour.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM