How to create a reusable component for large number of Buttons that open a Form

Viewed 68

library used: mui 5.4.1

To create a TableCell containing an IconButton that opens a Form, the code is written as follows.

const data = [
  {
    id: "001",
    name: "A",
    price: 2000
  },
  { id: "002", name: "B", price: 100 },

  ...

];

const SandboxTable = () => {
  return (
    <ThemeProvider theme={muiTheme}>
      <TableContainer>
        <Table>
          
           ...

            {data.map((datum) => (
              <TableRow key={datum.id}>
                <TableCell>{datum.id}</TableCell>
                <TableCell>{datum.name}</TableCell>
                <TableCell>{datum.price}</TableCell>
                <ApproveFormButtonCell
                  toolTip={"approve"}
                  id = {datum.id}
                  IconComponent={<CheckCircleOutlineIcon color={"success"} />}
                />
                <RejectFormButtonCell
                  toolTip={"Reject"}
                  name = {datum.name}
                  IconComponent={<CancelOutlinedIcon color="error" />}
                />
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </TableContainer>
    </ThemeProvider>
  );
};
const ApproveFormButtonCell = ({ toolTip, IconComponent }) => {
  const usePopoverProps = usePopover();
  return (
    <TableCell>
      <IconButtonWithTooltip
        toolTip={toolTip}
        onClick={usePopoverProps.handleOpen}
        IconComponent={IconComponent}
      />
      <BasePopover usePopverProps={usePopoverProps}>
        <ApproveForm id={id} handleClose={usePopoverProps.handleClose} />
      </BasePopover>
    </TableCell>
  );
};

Then I have to create a new ButtonCell component every time a new button is added.

To avoid this, when ApproveForm is used in SandboxTable, handleClose could not be received.

<ApproveFormButtonCell
  toolTip={"approve"}
  id = {datum.id}
  IconComponent={<CheckCircleOutlineIcon color={"success"} />}
/>
  <ApproveForm handleClose={??}/>
</ApproveFormButtonCell>

I need a lot of buttons open form. Any good answers to solve this situation?

codesandbox

1 Answers

To keep from making a one-off of every sort and type of form button cell component you can abstract the common behavior/UI, i.e. the IconButtonWithTooltip and BasePopover components, into a generic component and pass in as a prop the content that is different. In this case it seems the form component is what is different.

Create a general purpose component that utilizes the power of a render prop, i.e. a prop that is a function called during the render. This render prop will pass the close handler as an argument.

Example:

const FormButton = ({ toolTip, IconComponent, renderForm }) => {
  const popoverProps = usePopover();
  return (
    <>
      <IconButtonWithTooltip
        toolTip={toolTip}
        onClick={popoverProps.handleOpen}
        IconComponent={IconComponent}
      />
      <BasePopover usePopverProps={popoverProps}>
        {renderForm({ handleClose: popoverProps.handleClose })}
      </BasePopover>
    </>
  );
};

Example usage:

import CheckCircleOutlineIcon from "@mui/icons-material/CheckCircleOutline";
import CancelOutlinedIcon from "@mui/icons-material/CancelOutlined";
import FormButton from "./FormButton";
import RejectForm from "./RejectForm";
import ApproveForm from "./ApproveForm";

...

<TableBody>
  {data.map((datum) => (
    <TableRow key={datum.id}>
      <TableCell>{datum.id}</TableCell>
      <TableCell>{datum.name}</TableCell>
      <TableCell>{datum.price}</TableCell>
      <TableCell>
        <FormButton
          toolTip={"approve"}
          IconComponent={<CheckCircleOutlineIcon color={"success"} />}
          renderForm={({ handleClose }) => (
            <ApproveForm id={datum.id} handleClose={handleClose} />
          )}
        />
      </TableCell>
      <TableCell>
        <FormButton
          toolTip={"Reject"}
          IconComponent={<CancelOutlinedIcon color="error" />}
          renderForm={({ handleClose }) => (
            <RejectForm handleClose={handleClose} name={datum.name} />
          )}
        />
      </TableCell>
    </TableRow>
  ))}
</TableBody>

Edit how-to-create-a-reusable-component-for-large-number-of-buttons-that-open-a-form

Related