Why doesn't react-modal use imperative style?
I mean, following:
class MyComponent extends Component {
constructor() {
super();
...
this.modal = ...
...
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.modal.open(<div>Some content of modal.</div>);
}
render() {
return (<button onClick = {this.handleClick} >Click me to open modal</button>);
}
}
Hi @Webbrother, do you mean expose the open/close methods?
@diasbruno correct.
Can you provide a case where this can be helpful? (Of course there is, but just so we can see where isOpen attribute is not sufficient).
@diasbruno I've provided some dummy example in the first message. Actually my question doesn't mean that current implementation bad or good. My question just "Why?". My question more about conception. IMO modal is global UI element, and it should not be a child of MyComponent.
So I just thought that
...
render() {
<div>
<SomeComponent />
<Modal>...</Modal>
</div>
}
is a bit confusing. We declare <Modal> like child of my current component, but in fact it is not a child, because it is global UI element.
@Webbrother Sure. Just trying to figure it out how this can help.
...but in fact it is not a child, because it is global UI element.
react-modal doesn't works as a singleton instance, you can instantiate as many modals as you need and even nest than.
We declare
like child of my current component,...
This gives cohesion, to instantiate where it is used.
Hope this explains how this library works.
Let me know if you have other questions.
Thanks.
@diasbruno Thank you. But IMO imperative style can also process mentioned use cases (multiple instances (just call this.modal.open() twice...), nesting, etc...)
What problems imperative style can cause?
It's just that the current API is what the author (and pretty much the community) prefers. If you prefer an imperative API, you can wrap this component to do as you see fit.
class Modal extends React.Component {
state = {
isOpen: false
}
render() {
return (
<ReactModal {...this.props} isOpen={this.state.isOpen} />
)
}
open() {
this.setState({ isOpen: true })
}
close() {
this.setState({ isOpen: false })
}
}
I liked the API above 4 years ago, but came to personally dislike this API for the ff (but not limited to) reasons:
ref instances. If anything, it's my last option.Disclaimer: I'm not a contributor to this project, but I hope this answers your question.
Declaring the state of the UI, rather than setting it imperatively, is at the core of React. This library simply reflects that. You can always find a way to bridge things to an imperative system if you need to, but it's natural that a React library will be declarative-first.
just wanted to cast another vote for an imperative API.
if the modal lives entirely in the render method, then its content has to live in the state/props.
compare:
function (props) {
const handleClick = () => {
fetch('a thing').then(res => Modal.open(<BrandedAlert message={res} />))
}
return <button onClick={handleClick}>do a thing</button>
}
to
function (props) {
const [ fetchResponse, setFetchResponse ] = useState()
const [ modalOpen, setModalOpen ] = useState(false)
const handleClick = () => {
fetch('a thing').then(res => {
setFetchResponse(res)
setModalOpenTrue(res)
}))
}
return <>
<button onClick={handleClick}>do a thing</button>
<Modal isOpen={modalOpen}><BrandedAlert message={fetchResponse}/></modal>
</>
}
Pseudo code, but you get the idea.
now imagine a single component that opens multiple modals. state vars would quickly proliferate.
now imagine we wanna pass a function to
even cooler - is if the modal component (BrandedAlert in this example) could close with a response (resolve)
would allow stuff like:
Modal.open(<BrandedPrompt />).then(response => fetch( .... ))
EDIT: for anyone who comes across this later - I've started a bare-bones implementation of an imperative modal API
https://github.com/nihlton/react-imperial-modal
needs work - but its a start.
Most helpful comment
It's just that the current API is what the author (and pretty much the community) prefers. If you prefer an imperative API, you can wrap this component to do as you see fit.
I liked the API above 4 years ago, but came to personally dislike this API for the ff (but not limited to) reasons:
refinstances. If anything, it's my last option.Disclaimer: I'm not a contributor to this project, but I hope this answers your question.