-
Notifications
You must be signed in to change notification settings - Fork 171
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rewrite V4 for React 16 #157
Comments
In case it isn't common knowledge, react 16 is including a new API for portals. May be useful to take that into consideration |
@petejodo and it's now official! React.createPortal |
It lives on ReactDOM, not React. :-) |
I've been thinking a lot about modals recently. If we have some Now let's also say you have multiple touch points on the page that would trigger the login modal. You create some On a site where you have multiple developers, you may end up having code that looks like this then: // Feature1.jsx
const Feature1 = props => (
<div>
<SomeContent />
<button onClick={props.openAuthModal}>Login to edit content</button>
<LoginModal isOpen={props.authOpen} />
</div>
);
// Feature2.jsx
const Feature2 = props => (
<div>
<SomeMessageThread />
<button onClick={props.openAuthModal}>Login to add message</button>
<LoginModal isOpen={props.authOpen} />
</div>
);
// Parent.jsx
class Parent extends React.Component {
constructor(props) {
this.openAuthModal = this.openAuthModal.bind(this);
this.state = { authOpen: false };
}
openAuthModal() {
this.setState(() => ({ authOpen: true }));
}
render() {
return (
<div>
<Feature1 authOpen={this.state.authOpen} openAuthModal={this.openAuthModal} />
<Feature2 authOpen={this.state.authOpen} openAuthModal={this.openAuthModal} />
</div>
);
); The obvious issue is, when Parent's state is
Each option has its own issues though. For option 1, what happens over time is that all modals will get pulled to the top of the tree or if you use something like const MyRoute = () => (
<div>
{/* route contents */}
<LoginModal />
<TFAModal />
<PostMessageModal />
<EditContentModal />
{/* etc... */}
</div>
); Having to do this defeats the purpose of For option 2, one issue is when you want to open the modal on page load, for example; which instance of the modal should be rendered? You could create a All of this becomes even more complicated when you want to create flows for modals. For example, maybe sometimes LoginModal should continue on to a TFAModal (two-factor auth). You then have to make a decision on whether you just change the contents within the modal or close the first modal and then open the 2nd. If you change the content within the modal that means you can't animate the modal itself for the transition. If you close the 1st and then open the 2nd modal, depending on how you handled the original issue, causes its own headaches. I think this all stems from the disconnect between the implementation of modals and what they actually are from a design concept. Modals are essentially singletons from a design standpoint. While you could have a set of components with their own data and each needs to open a modal, only one modal can be open at a time (again, from a design standpoint). So what really should be happening, is the props get portal'd to a single While Also, while I was thinking about this, I couldn't help but think of Any discussion on this would be very useful. |
If I understand the way we use them at Facebook correctly, we have |
@petejodo That's a good note. I would probably use the first solution - move the modal to common parent. If there's a modal that needs to be open from multiple places, use redux and keep it somewhere near the app root.
Hm, I am not entirely following this. I think you can do this already? If you don't want to portal the whole component but only the props, you can use redux (or common state)?
That seems like a strong assumption (especially if modal === portal). Are there some specific changes in react-portal that could better support your use-case? Maybe react-gateway is a better fit if you don't mind context based solution with targets & sources. |
A colleague of mine and I were discussing this one day and figured we wanted a solution similar to what @gaearon said they do at facebook. Curious as to why it's done outside of React though. I assume it's some external requirement or just some older JS module that pre-dates React. @gaearon, if you had multiple @tajo sorry I was kind of spitting out common issues I've come across, without any consideration to actual features that would potentially make it into |
Yea, we have a whole system specifically for this that predates React. |
It tracks them separately but I think it can enforce that only one is visible. I’m not sure really. Modals can specify options and maybe there’s a way to specify that some modal should always be “alone” on the screen. I can check later. |
@tajo, In this solution I feel like portals aren't needed but correct me if I'm wrong. |
^^ The main post was updated. Please read and help with testing! |
^^ Sorry for that to all contributors. V3 was a mess and impossible to maintain. I feel much much better about V4. (Thanks React team for the new API!) Let's jumpstart this project! |
You probably want to update the logic in https://github.com/tajo/react-portal/blob/master/src/PortalWithState.js#L69. It should use React event propagation rather than DOM propagation, so that nested portals work correctly. |
@tajo thanks for the work for v4! I said I would respond later with tools I'd want for handling modals so I figured I'd close that loop. My goal is to be able to use modals as declaratively as possible so what I came up with is a sort of combo of this package and You'd place the <Foo>
<button>Open Modal</button>
<Modal>
<Bar />
</Modal>
</Foo> Then there'd be some <App>
<ModalStage />
<Foo />
</App> Now the Now This I believe would allow easily constructing multi-step modal flows by using a <Foo>
<Switch on={this.state.currentStep}>
<Modal>One</Modal>
<Modal>Two</Modal>
</Switch>
</Foo> This all seems very out-of-scope for this package so you can disregard it for the sake of this package but I'm curious what your opinion is of that idea? Also @gaearon, as someone who is familiar with react internals, I'm curious what your opinion is of the method that edit also sorry for hijacking this issue thread, maybe this is not the appropriate place for this since it should be about the v4 rewrite |
@tajo would you consider putting Not that it's a huge deal obviously, but it just seems like |
@bradleyayers Example? @petejodo Looks reasonable if you need to handle complex modal flows. You can still use v4 @ianstormtaylor File size is not a concern since there's now ES export and tools like Webpack will do tree-shaking out of the box. Agree, that most people should use just |
I have found an issue in 4.0.0-beta.1 with react 16. I don't know if you want me to open a new issue or report in this thread. The problem when closing
|
@jalopez If you can create a ticket that would be great! I would like to keep this thread for discussion about overall design and progress towards stable release than specific issues. |
@jalopez Fixed and released as |
|
And what about |
@evgenyrodionov Can you please open a new issue for that? I still don't understand why people want className for the root div. |
EDIT 10/1/2017:
This is an umbrella ticket for new v4. This library got a complete and long deserved overhaul. The biggest changes:
Portal
component into two components (stateless and stateful)Check the main README.md. It documents the new components and their APIs. I am really interested in your feedback! I feel that function as a child is the right pattern for the stateful
<PortalWithState/>
component and provides nice level of flexibility.You can install it as:
Roadmap for stable V4:
I would like to release the stable v4 version in a month (November 1st).
The text was updated successfully, but these errors were encountered: