41 comments

[ 433 ms ] story [ 2466 ms ] thread
Ah this is cool, like ember-wormhole in the ember world!

How were React devs doing modals, etc before?

It was pretty common to use https://github.com/tajo/react-portal for modals before React 16. It provided most (or all, I haven't really compared yet) of the functionality React 16 provides now so they've re-written it to just be a nice wrapper around the `createPortal` API.
Just use ReactDOM.render into a separate, top-level <div> that is usually empty. And then have the close button of the modal call ReactDOM.unmountComponentAtNode.

Alternatively, don't bother with all of this and just mount the modal into your children. Use CSS `position: absolute/fixed` to position it. Of course this assumes your ancestor elements don't have certain properties like `position: relative` or `transform` set, but this is usually not a problem.

A pop-up can be dragged onto a second monitor, for example, whereas a modal cannot.
OP was asking about how to do modals, not comparing a modal vs a pop-up.
There's nothing stopping you from extending your browser so that it's as wide as all your screens.
Append the modal component to the react app element, and then change the app state to open it. The disadvantage is that your modal exists outside of the component that opens it, so you can't pass in props from parent to child. But as long as the triggering component and the modal have access to the same app state store it's not a problem, and fairly clean.
It's probably just me, but I don't get what is cool about rendering in another window. Also, I generally don't like it if an app uses more than one window, so I'm not sure what this is useful for.
Can be useful when you have multiple monitors and don't want to clutter the main window, especially for single page apps or visualization/monitoring things.

I have done my own take at this since some times but vanilla only https://github.com/grz0zrg/wui where any of the dialog widget can be detached off the main window keeping the same content & state. A feature i never saw in any web apps but saw often on desktop apps, nice to see that some peoples think of this sort of thing with cleaner approach!

Managed to break your demo, open a modal from the right attached panel, make that modal a new window (button next to close button), close that new window, everything is stuck with the black alpha on top. Pressing Esc in that state, makes the main window disappear...
(comment deleted)
I would prefer opening the same url in a new browser window, rather than the app opening the window for me. This would also allow me to use my window-manager's built-in mechanisms for positioning the window programmatically.
> Can be useful when you have multiple monitors and don't want to clutter the main window, especially for single page apps or visualization/monitoring things.

Yep, this is precisely the use-case I would have for this in loom-viewer[0], a SPA data viewer I'm developing for the Loom file format[1] (think large genomic data matrices + metadata). It has a lot of scatter plots and bar charts, and for people with multiple monitors using a separate window as a pop-out would be quite beneficial. It also would make it easier to print out the graphs (which I find silly, but it's a thing researchers do).

I've looked at golden-layout before, but it doesn't play nice with redux at the moment[1]. Since I'm already on React 16 this might be what I'm looking for.

[0] http://loom.linnarssonlab.org/

[1] http://loompy.org/

[2] http://golden-layout.com/

Hi, I'm a Redux maintainer. Could you clarify what you mean by "doesn't play nice with Redux"?
Hi!

Well, note that I say that golden-layout does not play nice with Redux, not the other way around. It's not Redux being problematic here, as far as I can tell.

There's an open issue on their github repo asking for examples of how to integrate it:

https://github.com/deepstreamIO/golden-layout/issues/280

Maybe things have improved since I've last looked at it, but when I tried a few months ago, it seemed like it would require quite a bit of change in my code to get it up and running

By comparison, this new React 16 solution looks like it's a lot simpler to integrate in my existing code.

(comment deleted)
Portals can render your branch anywhere, inside the dom or outside in another. The cool thing is that it maintains current state, props and context, even when it's rendered elsewhere. That is insanely useful for common menus, overlaps, popups, annotations, when your container has overflow:hidden and you need to break out, etc. Used to be hacky or hard to realize, now all that's needed is returning a ReactDOM.createPortal(child, dom).
It's useful in enterprise apps.

You have three projects/clients/orders/enquiries/purchase orders/invoices/etc. You want to compare them/discuss them/etc.

You need to be able to switch between them.

It is very common for those kind of apps to get requests that lists/tables open a new window on link click.

The first thing that comes to mind is a gaming app where your main browser is the lobby but the windows are actual game instances. There's a site called global poker that does this for poker instances and it's clean / useful for this kind of use case.
This was always possible in React. I used it to render the redux-devtools in its own window (before there was a browser plugin): https://gist.github.com/tlrobinson/1e63d15d3e5f33410ef7
Yes, I didin't read the whole thing so I don't know if it applies here, but portals have an additional property:

Events fired in the portal bubble up the vdom tree up to the component that mounted the portal (and then further upwards to the main vdom root), rather than up the real dom up to the popup window root.

That's establishing a separate component tree. This is one single component tree, hosted in the parent window. That was never possible until portals landed.
You could have it like this:

    <Parent>
      <MyPortal root={element}>
        <h1>Howdy!</h1>
      </MyPortal>
    </Parent>
Where MyPortal actually renders its children in another element. Single component tree, multiple DOM roots. What portals add is the propagation of events through the portal.
How are portals implemented? Are they using broadcastchannel API or postmessage, etc, to communicate between the windows in the same app?
Another reason you might want to use this technique is to render something into an iframe
This interacts poorly with the built-in script blocking in chrome. You can't enable JavaScript in the about:blank window, so the buttons in it don't do anything. This is a pretty serious issue.

Probably more of a chrome bug though I guess, it should inherit script blocking from the spawning page.

This is a bad idea for any serious app. I inherited a framework that did this, and it performed terribly. Not to mention, it’s an exercise in discovering browser edge cases you would have otherwise never had to worry about. Use postMessage or localStorage to communicate between windows. Don’t use window handles.
Teah, it’s a clever (if not new) hack but there already exists a sane way of doing this
Yeah, I use MessageChannel ports whenever communicating across domains: extensions, Workers, etc.

That was I can abstract it into convenience classes for connecting, event listening, etc.

I suppose the newer BroadcastChannel would be an option too, for high performance multi-window usage.
Could this be exploited for state rehydration across multiple tabs?
React 16?

Anglar 1 was around for a while. There was a big fuss about Angular 2 being incompatible, and before I have had a chance to look at it, we are on Angular 4.

Now we are on React 16.

As if the JavaScript ecosystem wasn't bad enough, we now seem have an extra problem of completely silly release numbers. (I do 80% back end work, but in this day and age its hard not to use JavaScript. I took an interest in these frameworks a couple of years back and didn't gt much chance to follow up since then. Version numbering like this discourage me from finding out more.)

React has extremely careful versioning with a precise internal definition of what a "breaking change" is. Judging React by Angular's terrible version numbers doesn't seem fair to me.

They're on v16 because they increment the number any time they make a change that isn't 100% drop-in backwards compatible with the previous version, with a deprecation cycle when possible beforehand. Apps that function without deprecation warnings can update immediately when a new release drops.

Ultimately they are where they are because they were of a change they made when they released v15. Really, it's more like v3, but they kept the numbering consistent with how people talked about it. https://reactjs.org/blog/2016/02/19/new-versioning-scheme.ht...

honestly just caused me to realize I'm not even positive what version my last react app was in.. I thought I was 'current' but I know it was a single digit number so I guess I wasn't.
If it's backward compatible, its not so bad, but whole number releases usually imply that there will be some breaking changes (or they do to me at least).
Major version numbers are now actually reflecting major changes. If you're reading an article for React 16 and have strange issues because you're on React 12, it's going to be a lot more obvious than if we're just bumping up minor versions. You can also be more sure that a if you're on 16.0.4, and the article is for 16.0.1 - that you're less likely to run into issues.

It's the same reason chrome is on 62 and Firefox is launching 57 at the end of the month.

Semantic versioning gets bigger numbers faster, but it's better for developers.

If you want to critize JavaScript, you don't have to make things up. It has real flaws.