Allow Portals to be used for Reparenting
See original GitHub issueDo you want to request a feature or report a bug?
feature
What is the current behavior?
Reparenting is an unsolved issues of React(DOM). So far, it was possible to hack around the missing support for it by relying on unstable API (unstable_renderSubtreeIntoContainer
) to render and update a subtree inside a different container. It’s important to note that this API was using React’s diffing algorithm so that, similar to ReactDOM.render()
, it is possible to keep components mounted.
ReactDOM.render(<Foo />, container);
// This won't get <Foo /> to be unmounted and mounted again:
ReactDOM.render(<Foo />, container);
ReactDOM.unstable_renderSubtreeIntoContainer(
parentComponent,
<Foo />,
container
);
// This also won't get <Foo /> to be unmounted and mounted again, no matter if
// we change parentComponent (and thus call it from a different parent):
ReactDOM.unstable_renderSubtreeIntoContainer(
parentComponent,
<Foo />,
container
);
However this unstable API is going to be deprecated soon and recent features like the introduction of the new context API introduced additional issues.
As an alternative to this unstable API, ReactDOM.createPortal(children, container)
was introduced. However this API is unsuitable for the reparenting issue since it will always create a new mount point inside the container
instead of applying the diffing when called from a different parent (Check out this CodeSandbox where calling the portal from a different portal will cause the <Leaf />
to have a new uuid). The reason for this is that we want multiple portals to be able to render inside the same container
which makes perfect sense for more common use cases like popovers, etc.
Before we’re going to remove unstable_renderSubtreeIntoContainer
, I suggest we find a way to portal into a specific node instead of appending to it so that we can diff its contents instead (or implement a solution for #3965 although that seems to be more complicated), similar to unstable_renderSubtreeIntoContainer
.
Issue Analytics
- State:
- Created 5 years ago
- Reactions:18
- Comments:29 (9 by maintainers)
To avoid using unstable/deprecated API, here is an example that might be helpful to anyone looking for a practical approach of re-parenting using portals (CodePen):
I have a use case: A dashboard with widgets rendered in columns with drag & drop between them (using react-beautiful-dnd).
Each column is a Droppable here and the individual widgets are the Draggable children of this Droppable.
The contents of each widget are completely dynamic and definitely stateful - each widget is pretty standalone and there can be many different kinds of them, so managing state on a higher level is impractical. For example, they can fetch data to display in charts, they can contain a search bar etc.
Reparenting is useful here because you clearly don’t want to re-fetch data, or lose you search bar value, when switching columns.
Not saying there is absolutely no way around this, but yeah, a native way to reparent probably would be nice? 😃