I am trying to create Tabs and have JSX Components dynamically placed into each Tab as content. I am using React and Polaris as I am creating a new Shopify App.
I cannot seem to work out how to do this - I am very new to Javascript/Typescript and even React.
I have all the Tabs working showing the correct details in each, but I cannot pull the child JSX 'DesignForm' and make it show as within the First Tab.
import React, { Children } from "react";
import { Card, Page, Layout, TextContainer, Image, Stack, Link, Heading, Tabs} from "@shopify/polaris";
import {ReactNode, useState, useCallback} from 'react';
import { DesignForm } from "../designform/DesignForm";
export function NavTabs() {
const [selected, setSelected] = useState(0);
interface childrenProps {
children: JSX.Element;
}
const index = ({ children }: childrenProps) => {
return (
<>
<DesignForm />
{children}
</>
);
};
const handleTabChange = useCallback(
(selectedTabIndex) => setSelected(selectedTabIndex),
[],
);
const tabs = [
{
id: 'all-customers-4',
content: 'All',
accessibilityLabel: 'All customers',
panelID: 'all-customers-content-4',
children: DesignForm,
},
{
id: 'accepts-marketing-4',
content: 'Accepts marketing',
panelID: 'accepts-marketing-content-4',
},
{
id: 'repeat-customers-4',
content: 'Repeat customers',
panelID: 'repeat-customers-content-4',
},
{
id: 'prospects-4',
content: 'Prospects',
panelID: 'prospects-content-4',
},
];
return (
<Card>
<Tabs
tabs={tabs}
selected={selected}
onSelect={handleTabChange}
disclosureText="More views"
>
<Card.Section title={tabs[selected].content}>
<p>Tab {selected} selected</p>
</Card.Section>
<Card.Section children={tabs[selected].children}></Card.Section>
</Tabs>
</Card>
);
}
CodePudding user response:
in
{
id: 'all-customers-4',
content: 'All',
accessibilityLabel: 'All customers',
panelID: 'all-customers-content-4',
children: DesignForm,
}
Your children (i.e DesignForm) is a function here you should set the children to your component instead
{
id: 'all-customers-4',
content: 'All',
accessibilityLabel: 'All customers',
panelID: 'all-customers-content-4',
children: <DesignForm/>,
}
You also could replace
<Card.Section children={tabs[selected].children}></Card.Section>
by
<Card.Section>
{tabs[selected].children}
</Card.Section>
CodePudding user response:
Few pointers
Move this outside of the component for performance reasons, and React components should start with Capital letter interface childrenProps { children: JSX.Element; }
// change from index to Index
const Index = ({ children }: childrenProps) => {
return (
<>
<DesignForm />
{children}
</>
);
};
If this is static move it outside the component, as it will be recreated in every render
const tabs = [
{
id: 'all-customers-4',
content: 'All',
accessibilityLabel: 'All customers',
panelID: 'all-customers-content-4',
},
{
id: 'accepts-marketing-4',
content: 'Accepts marketing',
panelID: 'accepts-marketing-content-4',
},
{
id: 'repeat-customers-4',
content: 'Repeat customers',
panelID: 'repeat-customers-content-4',
},
{
id: 'prospects-4',
content: 'Prospects',
panelID: 'prospects-content-4',
},
];
Create a component map, or something similar to this
const componentMap = {
['all-customers-4']: DesignForm,
// ... more components can be added in the future
}
const EmptyComponent = () => null;
export function NavTabs() {
const [selected, setSelected] = useState(0);
const handleTabChange = useCallback(
(selectedTabIndex) => setSelected(selectedTabIndex),
[],
);
const ChildComponent = useMemo(() => {
return componentMap[selected] ?? EmptyComponent
}, [selected])
return (
<Card>
<Tabs
tabs={tabs}
selected={selected}
onSelect={handleTabChange}
disclosureText="More views"
>
<Card.Section title={tabs[selected].content}>
<p>Tab {selected} selected</p>
<ChildComponent />
</Card.Section>
<Card.Section children={tabs[selected].children}></Card.Section>
</Tabs>
</Card>
);
}
Hope this helps you in some way to find a good solution
Cheers