Home > Software engineering >  render MUI components from an array of data and display the first one differently
render MUI components from an array of data and display the first one differently

Time:10-21

Here I am trying to render the contents of Accordion through a list array passing down the props to a component. I kind of understand where the issue is but I don't know how else I can call the component and pass the props. Below is my code.

Code of the parent component

const Sandbox = () => {

let summaryContents: any[] = [
    {
      Title: "Construction costs",
      TotalPrice: "$25000",
      Subcontents: [
        {
          Subtitle: "Sanitation",
          SubtitlePrice: "$5000",
        },
        {
          Subtitle: "PoolLights",
          SubtitlePrice: "$5000",
        },
        {
          Subtitle: "PoolCleaner",
          SubtitlePrice: "$15000",
        },
      ],
    },
    {
      Title: "Pool interior costs",
      TotalPrice: "$20000",
      Subcontents: [
        {
          Subtitle: "Title1",
          SubtitlePrice: "$5000",
        },
        {
          Subtitle: "Title2",
          SubtitlePrice: "$10000",
        },
        {
          Subtitle: "Title3",
          SubtitlePrice: "$5000",
        },
      ],
    },
];


  let summaryContentsList: any[] = [];

  summaryContents.forEach((item: any, index: number) => {
    summaryContentsList.push(
      <QuoteSummary
        
        Title={item.Title}
        TotalPrice={item.TotalPrice}
        Subtitle={item.Subcontents.Subtitle}
        SubtitlePrice={item.Subcontents.SubtitlePrice}
      />
    );
  });
  return (
    <>
      
      {summaryContentsList}
    </>
  );
};

Code for the child component

const QuoteSummary: FC<QuoteSummaryProps> = (props: QuoteSummaryProps) => {
  const classes = useStyles();
  return (
    <QuoteCard>
      <Typography variant="h1" sx={{ paddingBottom: 2 }}>
        Quote Summary
      </Typography>
      <DialogCloseButton onClose={clicked} />

      <Accordion
        className={classes.accordion}
        sx={{
          paddingTop: 0,
        }}
      >
        <AccordionSummary
          expandIcon={<ExpandMoreIcon />}
          aria-controls="panel1a-content"
          id="panel1a-header"
        >
          <Typography variant="h3">{props.Title}</Typography>
          <Typography variant="h3" sx={{ paddingLeft: 10 }}>
            {props.TotalPrice}
          </Typography>
        </AccordionSummary>
        <AccordionDetails>
          <Typography>{props.Subtitle}</Typography>
          <Typography>{props.SubtitlePrice}</Typography>
        </AccordionDetails>
      </Accordion>
    </QuoteCard>
  );
};

enter image description here

This is how it looks where as I wanted to render the Title only once and accordion contents below. What would be the approach I will have to follow

CodePudding user response:

You can put the QuoteCard outside and only place Accordion item in the child component:

const QuoteSummary: FC<QuoteSummaryProps> = (props: QuoteSummaryProps) => {
  return (
    <Accordion>
      {...}
    </Accordion>
  );
};
<QuoteCard>
  <Typography variant="h6" sx={{ paddingBottom: 2 }}>
    Quote Summary
  </Typography>
  <DialogCloseButton onClose={() => {}} />

  {summaryContents.map((item) => (
    <QuoteSummary
      Title={item.Title}
      TotalPrice={item.TotalPrice}
      Subtitle={item.Subcontents.Subtitle}
      SubtitlePrice={item.Subcontents.SubtitlePrice}
    />
  ))}
</QuoteCard>

EDIT: Another approach is to render the title conditionally in the child component based on the props provided from the parent:

const QuoteSummary: FC<QuoteSummaryProps> = (props: QuoteSummaryProps) => {
  return (
    <QuoteCard>
      {props.displayTitle && (
        <Typography variant="h6" sx={{ paddingBottom: 2 }}>
          Quote Summary
        </Typography>
      )}
      <DialogCloseButton onClose={() => {}} />
      <Accordion>
        {...}
      </Accordion>
    </QuoteCard>
  );
};
<>
  {summaryContents.map((item, i) => (
    <QuoteSummary
      displayTitle={i === 0}
      Title={item.Title}
      TotalPrice={item.TotalPrice}
      Subtitle={item.Subcontents.Subtitle}
      SubtitlePrice={item.Subcontents.SubtitlePrice}
    />
  ))}
</>

Codesandbox Demo

CodePudding user response:

You can create a render function for array items and use them like this:

const Sandbox = () => {
  const summaryContents: any[] = [
    {
      Title: "Construction costs",
      TotalPrice: "$25000",
      Subcontents: [{
          Subtitle: "Sanitation",
          SubtitlePrice: "$5000",
        },
        {
          Subtitle: "PoolLights",
          SubtitlePrice: "$5000",
        },
        {
          Subtitle: "PoolCleaner",
          SubtitlePrice: "$15000",
        },
      ],
    },
    {
      Title: "Pool interior costs",
      TotalPrice: "$20000",
      Subcontents: [{
          Subtitle: "Title1",
          SubtitlePrice: "$5000",
        },
        {
          Subtitle: "Title2",
          SubtitlePrice: "$10000",
        },
        {
          Subtitle: "Title3",
          SubtitlePrice: "$5000",
        },
      ],
    },
  ];

  const renderContent = (item: any) => (
     <QuoteSummary
        Title={item.Title}
        TotalPrice={item.TotalPrice}
        Subtitle={item.Subcontents.Subtitle}
        SubtitlePrice={item.Subcontents.SubtitlePrice}
      />
  );

  return (
    <>
      {summaryContents.map(renderContent)}
    </>
  );
};
  • Related