Reusability of a modal in ReactJS

Multi tool use
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
add a comment |
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
add a comment |
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
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
javascript reactjs typescript reusability
asked Jan 2 at 15:59
nephewsnephews
31
31
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
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>
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 aonCloseClick
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
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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>
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 aonCloseClick
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
add a comment |
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>
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 aonCloseClick
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
add a comment |
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>
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>
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 aonCloseClick
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
add a comment |
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 aonCloseClick
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
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
5keKNjWhkMJAFC54cbEc,d01w55