Reusability of a modal in ReactJS












0















Making a modal dynamic without too much code duplication. How do I go about this?



I've used render props to separate the state from the layout.



interface State {
open: boolean;
}

interface InjectedModalProps {
onCloseModal: () => void;
onOpenModal: () => void;
open: boolean;
}

interface ModalProps {
children(props: InjectedModalProps): ReactNode;
}
class ModalProvider extends Component<ModalProps, State> {
state: State = {
open: false
};
onOpenModal = () => {
this.setState({ open: true });
};

onCloseModal = () => {
this.setState({ open: false });
};

render() {
const { open } = this.state;
const { children } = this.props;
return (
<Fragment>
{children({
onCloseModal: this.onCloseModal,
onOpenModal: this.onOpenModal,
open
})}
</Fragment>
);
}
}

const BathroomModal: FunctionComponent<Props> = ({ edit }) => (
<ModalProvider>
{({ onCloseModal, open, onOpenModal }) => {
return (
<Fragment>
<Modal open={open} center onClose={onCloseModal}>
<Container>
<h1>Badkamer toevoegen</h1>
{edit && <DeleteButton>Verwijderen</DeleteButton>}
<Divider />
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Est dolores incidunt ipsa,
earum nobis beatae facilis, dolore harum vitae nihil molestias repudiandae non quisquam
ab. Omnis unde atque voluptate ipsa!
</p>
<ContentBlock>
<h4>Type</h4>
<BathroomInputTypes />
<h4>Toilet</h4>
<Field name="toilet" options={[0, 1, 2, 3, 4, 5]} component={InputWithToggle} />
<h4>Douche</h4>
<Field name="shower" options={[0, 1, 2, 3, 4, 5]} component={InputWithToggle} />
<h4>Bad</h4>
<Field name="bath" options={[0, 1, 2, 3, 4, 5]} component={InputWithToggle} />
</ContentBlock>
<Divider />
<PrimaryButton onClick={onCloseModal} type="button">
{!edit ? 'Badkamer toevoegen' : 'Wijzigingen opslaan'}
</PrimaryButton>
</Container>
</Modal>
<SecondaryButton onClick={onOpenModal} type="button">
Badkamer toevoegen
</SecondaryButton>
</Fragment>
);
}}
</ModalProvider>
);


So this is what I've come up with. But I think it can be more reusable by extracting the Modal component into the ModalProvider. I could also put the trigger button in there as well. However, I also want the trigger button to be dynamic so I can for example use an icon instead of a button to open the modal.










share|improve this question



























    0















    Making a modal dynamic without too much code duplication. How do I go about this?



    I've used render props to separate the state from the layout.



    interface State {
    open: boolean;
    }

    interface InjectedModalProps {
    onCloseModal: () => void;
    onOpenModal: () => void;
    open: boolean;
    }

    interface ModalProps {
    children(props: InjectedModalProps): ReactNode;
    }
    class ModalProvider extends Component<ModalProps, State> {
    state: State = {
    open: false
    };
    onOpenModal = () => {
    this.setState({ open: true });
    };

    onCloseModal = () => {
    this.setState({ open: false });
    };

    render() {
    const { open } = this.state;
    const { children } = this.props;
    return (
    <Fragment>
    {children({
    onCloseModal: this.onCloseModal,
    onOpenModal: this.onOpenModal,
    open
    })}
    </Fragment>
    );
    }
    }

    const BathroomModal: FunctionComponent<Props> = ({ edit }) => (
    <ModalProvider>
    {({ onCloseModal, open, onOpenModal }) => {
    return (
    <Fragment>
    <Modal open={open} center onClose={onCloseModal}>
    <Container>
    <h1>Badkamer toevoegen</h1>
    {edit && <DeleteButton>Verwijderen</DeleteButton>}
    <Divider />
    <p>
    Lorem ipsum dolor sit amet consectetur adipisicing elit. Est dolores incidunt ipsa,
    earum nobis beatae facilis, dolore harum vitae nihil molestias repudiandae non quisquam
    ab. Omnis unde atque voluptate ipsa!
    </p>
    <ContentBlock>
    <h4>Type</h4>
    <BathroomInputTypes />
    <h4>Toilet</h4>
    <Field name="toilet" options={[0, 1, 2, 3, 4, 5]} component={InputWithToggle} />
    <h4>Douche</h4>
    <Field name="shower" options={[0, 1, 2, 3, 4, 5]} component={InputWithToggle} />
    <h4>Bad</h4>
    <Field name="bath" options={[0, 1, 2, 3, 4, 5]} component={InputWithToggle} />
    </ContentBlock>
    <Divider />
    <PrimaryButton onClick={onCloseModal} type="button">
    {!edit ? 'Badkamer toevoegen' : 'Wijzigingen opslaan'}
    </PrimaryButton>
    </Container>
    </Modal>
    <SecondaryButton onClick={onOpenModal} type="button">
    Badkamer toevoegen
    </SecondaryButton>
    </Fragment>
    );
    }}
    </ModalProvider>
    );


    So this is what I've come up with. But I think it can be more reusable by extracting the Modal component into the ModalProvider. I could also put the trigger button in there as well. However, I also want the trigger button to be dynamic so I can for example use an icon instead of a button to open the modal.










    share|improve this question

























      0












      0








      0








      Making a modal dynamic without too much code duplication. How do I go about this?



      I've used render props to separate the state from the layout.



      interface State {
      open: boolean;
      }

      interface InjectedModalProps {
      onCloseModal: () => void;
      onOpenModal: () => void;
      open: boolean;
      }

      interface ModalProps {
      children(props: InjectedModalProps): ReactNode;
      }
      class ModalProvider extends Component<ModalProps, State> {
      state: State = {
      open: false
      };
      onOpenModal = () => {
      this.setState({ open: true });
      };

      onCloseModal = () => {
      this.setState({ open: false });
      };

      render() {
      const { open } = this.state;
      const { children } = this.props;
      return (
      <Fragment>
      {children({
      onCloseModal: this.onCloseModal,
      onOpenModal: this.onOpenModal,
      open
      })}
      </Fragment>
      );
      }
      }

      const BathroomModal: FunctionComponent<Props> = ({ edit }) => (
      <ModalProvider>
      {({ onCloseModal, open, onOpenModal }) => {
      return (
      <Fragment>
      <Modal open={open} center onClose={onCloseModal}>
      <Container>
      <h1>Badkamer toevoegen</h1>
      {edit && <DeleteButton>Verwijderen</DeleteButton>}
      <Divider />
      <p>
      Lorem ipsum dolor sit amet consectetur adipisicing elit. Est dolores incidunt ipsa,
      earum nobis beatae facilis, dolore harum vitae nihil molestias repudiandae non quisquam
      ab. Omnis unde atque voluptate ipsa!
      </p>
      <ContentBlock>
      <h4>Type</h4>
      <BathroomInputTypes />
      <h4>Toilet</h4>
      <Field name="toilet" options={[0, 1, 2, 3, 4, 5]} component={InputWithToggle} />
      <h4>Douche</h4>
      <Field name="shower" options={[0, 1, 2, 3, 4, 5]} component={InputWithToggle} />
      <h4>Bad</h4>
      <Field name="bath" options={[0, 1, 2, 3, 4, 5]} component={InputWithToggle} />
      </ContentBlock>
      <Divider />
      <PrimaryButton onClick={onCloseModal} type="button">
      {!edit ? 'Badkamer toevoegen' : 'Wijzigingen opslaan'}
      </PrimaryButton>
      </Container>
      </Modal>
      <SecondaryButton onClick={onOpenModal} type="button">
      Badkamer toevoegen
      </SecondaryButton>
      </Fragment>
      );
      }}
      </ModalProvider>
      );


      So this is what I've come up with. But I think it can be more reusable by extracting the Modal component into the ModalProvider. I could also put the trigger button in there as well. However, I also want the trigger button to be dynamic so I can for example use an icon instead of a button to open the modal.










      share|improve this question














      Making a modal dynamic without too much code duplication. How do I go about this?



      I've used render props to separate the state from the layout.



      interface State {
      open: boolean;
      }

      interface InjectedModalProps {
      onCloseModal: () => void;
      onOpenModal: () => void;
      open: boolean;
      }

      interface ModalProps {
      children(props: InjectedModalProps): ReactNode;
      }
      class ModalProvider extends Component<ModalProps, State> {
      state: State = {
      open: false
      };
      onOpenModal = () => {
      this.setState({ open: true });
      };

      onCloseModal = () => {
      this.setState({ open: false });
      };

      render() {
      const { open } = this.state;
      const { children } = this.props;
      return (
      <Fragment>
      {children({
      onCloseModal: this.onCloseModal,
      onOpenModal: this.onOpenModal,
      open
      })}
      </Fragment>
      );
      }
      }

      const BathroomModal: FunctionComponent<Props> = ({ edit }) => (
      <ModalProvider>
      {({ onCloseModal, open, onOpenModal }) => {
      return (
      <Fragment>
      <Modal open={open} center onClose={onCloseModal}>
      <Container>
      <h1>Badkamer toevoegen</h1>
      {edit && <DeleteButton>Verwijderen</DeleteButton>}
      <Divider />
      <p>
      Lorem ipsum dolor sit amet consectetur adipisicing elit. Est dolores incidunt ipsa,
      earum nobis beatae facilis, dolore harum vitae nihil molestias repudiandae non quisquam
      ab. Omnis unde atque voluptate ipsa!
      </p>
      <ContentBlock>
      <h4>Type</h4>
      <BathroomInputTypes />
      <h4>Toilet</h4>
      <Field name="toilet" options={[0, 1, 2, 3, 4, 5]} component={InputWithToggle} />
      <h4>Douche</h4>
      <Field name="shower" options={[0, 1, 2, 3, 4, 5]} component={InputWithToggle} />
      <h4>Bad</h4>
      <Field name="bath" options={[0, 1, 2, 3, 4, 5]} component={InputWithToggle} />
      </ContentBlock>
      <Divider />
      <PrimaryButton onClick={onCloseModal} type="button">
      {!edit ? 'Badkamer toevoegen' : 'Wijzigingen opslaan'}
      </PrimaryButton>
      </Container>
      </Modal>
      <SecondaryButton onClick={onOpenModal} type="button">
      Badkamer toevoegen
      </SecondaryButton>
      </Fragment>
      );
      }}
      </ModalProvider>
      );


      So this is what I've come up with. But I think it can be more reusable by extracting the Modal component into the ModalProvider. I could also put the trigger button in there as well. However, I also want the trigger button to be dynamic so I can for example use an icon instead of a button to open the modal.







      javascript reactjs typescript reusability






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Jan 2 at 15:59









      nephewsnephews

      31




      31
























          1 Answer
          1






          active

          oldest

          votes


















          0














          I think this is a good start. I would suggest that you think about all of the things a modal generally has (in the same places) and put them into the ModalProvider. As you suggested, I would add the close button as well as a conditional "OK" button or something like that in the bottom right corner if you need a Dialog style modal with an action button.



          The text for these buttons, can be changed through props, but they should always be buttons. Even if it's an icon, it should probably be in a button component to maintain semantic HTML. You can pass in the close button value as a prop to the modal provider as something like this:



          <ModalProvider buttonText={<Icon type='close' {...props} />}>
          {... modal contents ...}
          </ModalProvider>





          share|improve this answer
























          • Yeah I was thinking about implementing it this way too. However, I was struggling with implementing the button in ModalProvider when its getting it from a prop. How would you suggest to do this? I mean I can't give {buttonText} an onClick action, right? Anyways, thanks for taking the time to help me!

            – nephews
            Jan 2 at 17:01











          • You can go about it two different ways. It's likely that your onclick method is always the same in the ModalProvider, or at least that there will be one, so you can set it in the ModalProvider. If you need to you can add a onCloseClick prop to it to change the functionality. Otherwise, you can give a component as a prop for the whole button closeButton={<Btn onclick={fn} />} or renderprop style closeButton={props => <Btn {...props} />}

            – tenor528
            Jan 2 at 17:12











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54009395%2freusability-of-a-modal-in-reactjs%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          0














          I think this is a good start. I would suggest that you think about all of the things a modal generally has (in the same places) and put them into the ModalProvider. As you suggested, I would add the close button as well as a conditional "OK" button or something like that in the bottom right corner if you need a Dialog style modal with an action button.



          The text for these buttons, can be changed through props, but they should always be buttons. Even if it's an icon, it should probably be in a button component to maintain semantic HTML. You can pass in the close button value as a prop to the modal provider as something like this:



          <ModalProvider buttonText={<Icon type='close' {...props} />}>
          {... modal contents ...}
          </ModalProvider>





          share|improve this answer
























          • Yeah I was thinking about implementing it this way too. However, I was struggling with implementing the button in ModalProvider when its getting it from a prop. How would you suggest to do this? I mean I can't give {buttonText} an onClick action, right? Anyways, thanks for taking the time to help me!

            – nephews
            Jan 2 at 17:01











          • You can go about it two different ways. It's likely that your onclick method is always the same in the ModalProvider, or at least that there will be one, so you can set it in the ModalProvider. If you need to you can add a onCloseClick prop to it to change the functionality. Otherwise, you can give a component as a prop for the whole button closeButton={<Btn onclick={fn} />} or renderprop style closeButton={props => <Btn {...props} />}

            – tenor528
            Jan 2 at 17:12
















          0














          I think this is a good start. I would suggest that you think about all of the things a modal generally has (in the same places) and put them into the ModalProvider. As you suggested, I would add the close button as well as a conditional "OK" button or something like that in the bottom right corner if you need a Dialog style modal with an action button.



          The text for these buttons, can be changed through props, but they should always be buttons. Even if it's an icon, it should probably be in a button component to maintain semantic HTML. You can pass in the close button value as a prop to the modal provider as something like this:



          <ModalProvider buttonText={<Icon type='close' {...props} />}>
          {... modal contents ...}
          </ModalProvider>





          share|improve this answer
























          • Yeah I was thinking about implementing it this way too. However, I was struggling with implementing the button in ModalProvider when its getting it from a prop. How would you suggest to do this? I mean I can't give {buttonText} an onClick action, right? Anyways, thanks for taking the time to help me!

            – nephews
            Jan 2 at 17:01











          • You can go about it two different ways. It's likely that your onclick method is always the same in the ModalProvider, or at least that there will be one, so you can set it in the ModalProvider. If you need to you can add a onCloseClick prop to it to change the functionality. Otherwise, you can give a component as a prop for the whole button closeButton={<Btn onclick={fn} />} or renderprop style closeButton={props => <Btn {...props} />}

            – tenor528
            Jan 2 at 17:12














          0












          0








          0







          I think this is a good start. I would suggest that you think about all of the things a modal generally has (in the same places) and put them into the ModalProvider. As you suggested, I would add the close button as well as a conditional "OK" button or something like that in the bottom right corner if you need a Dialog style modal with an action button.



          The text for these buttons, can be changed through props, but they should always be buttons. Even if it's an icon, it should probably be in a button component to maintain semantic HTML. You can pass in the close button value as a prop to the modal provider as something like this:



          <ModalProvider buttonText={<Icon type='close' {...props} />}>
          {... modal contents ...}
          </ModalProvider>





          share|improve this answer













          I think this is a good start. I would suggest that you think about all of the things a modal generally has (in the same places) and put them into the ModalProvider. As you suggested, I would add the close button as well as a conditional "OK" button or something like that in the bottom right corner if you need a Dialog style modal with an action button.



          The text for these buttons, can be changed through props, but they should always be buttons. Even if it's an icon, it should probably be in a button component to maintain semantic HTML. You can pass in the close button value as a prop to the modal provider as something like this:



          <ModalProvider buttonText={<Icon type='close' {...props} />}>
          {... modal contents ...}
          </ModalProvider>






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Jan 2 at 16:06









          tenor528tenor528

          8921017




          8921017













          • Yeah I was thinking about implementing it this way too. However, I was struggling with implementing the button in ModalProvider when its getting it from a prop. How would you suggest to do this? I mean I can't give {buttonText} an onClick action, right? Anyways, thanks for taking the time to help me!

            – nephews
            Jan 2 at 17:01











          • You can go about it two different ways. It's likely that your onclick method is always the same in the ModalProvider, or at least that there will be one, so you can set it in the ModalProvider. If you need to you can add a onCloseClick prop to it to change the functionality. Otherwise, you can give a component as a prop for the whole button closeButton={<Btn onclick={fn} />} or renderprop style closeButton={props => <Btn {...props} />}

            – tenor528
            Jan 2 at 17:12



















          • Yeah I was thinking about implementing it this way too. However, I was struggling with implementing the button in ModalProvider when its getting it from a prop. How would you suggest to do this? I mean I can't give {buttonText} an onClick action, right? Anyways, thanks for taking the time to help me!

            – nephews
            Jan 2 at 17:01











          • You can go about it two different ways. It's likely that your onclick method is always the same in the ModalProvider, or at least that there will be one, so you can set it in the ModalProvider. If you need to you can add a onCloseClick prop to it to change the functionality. Otherwise, you can give a component as a prop for the whole button closeButton={<Btn onclick={fn} />} or renderprop style closeButton={props => <Btn {...props} />}

            – tenor528
            Jan 2 at 17:12

















          Yeah I was thinking about implementing it this way too. However, I was struggling with implementing the button in ModalProvider when its getting it from a prop. How would you suggest to do this? I mean I can't give {buttonText} an onClick action, right? Anyways, thanks for taking the time to help me!

          – nephews
          Jan 2 at 17:01





          Yeah I was thinking about implementing it this way too. However, I was struggling with implementing the button in ModalProvider when its getting it from a prop. How would you suggest to do this? I mean I can't give {buttonText} an onClick action, right? Anyways, thanks for taking the time to help me!

          – nephews
          Jan 2 at 17:01













          You can go about it two different ways. It's likely that your onclick method is always the same in the ModalProvider, or at least that there will be one, so you can set it in the ModalProvider. If you need to you can add a onCloseClick prop to it to change the functionality. Otherwise, you can give a component as a prop for the whole button closeButton={<Btn onclick={fn} />} or renderprop style closeButton={props => <Btn {...props} />}

          – tenor528
          Jan 2 at 17:12





          You can go about it two different ways. It's likely that your onclick method is always the same in the ModalProvider, or at least that there will be one, so you can set it in the ModalProvider. If you need to you can add a onCloseClick prop to it to change the functionality. Otherwise, you can give a component as a prop for the whole button closeButton={<Btn onclick={fn} />} or renderprop style closeButton={props => <Btn {...props} />}

          – tenor528
          Jan 2 at 17:12




















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54009395%2freusability-of-a-modal-in-reactjs%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Angular Downloading a file using contenturl with Basic Authentication

          Olmecas

          Can't read property showImagePicker of undefined in react native iOS