Home > Mobile >  Adding JSX Element as a Property
Adding JSX Element as a Property

Time:11-30

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

  • Related