question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Allow Portals to be used for Reparenting

See original GitHub issue

Do 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:open
  • Created 5 years ago
  • Reactions:18
  • Comments:29 (9 by maintainers)

github_iconTop GitHub Comments

16reactions
vkatushenokcommented, Oct 11, 2018

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):

const appRoot = document.getElementById('app-root');

class Reparentable extends React.Component<{ el: HTMLElement }> {
  private readonly ref = React.createRef<HTMLDivElement>();

  componentDidMount() {
    this.ref.current!.appendChild(this.props.el);
  }

  render() {
    return <div ref={this.ref}/>;
  }
}

class Parent extends React.Component {
  private readonly childContainer: HTMLElement = document.createElement('div');
  state = {
    down: false,
  };

  handleClick = () => {
    this.setState(prevState => ({
      down: !prevState.down
    }));
  }

  render() {
    return (
      <div>
        <p>Down: {this.state.down + ''}</p>
        <button onClick={this.handleClick}>Click</button>
        {ReactDOM.createPortal(<Child />, this.childContainer)}
        <h2>Root 1</h2>
        <div key="1">
          {!this.state.down && <Reparentable el={this.childContainer} />}
        </div>
        <h2>Root 2</h2>
        <div key="2">
          {this.state.down && <Reparentable el={this.childContainer} />}
        </div>
      </div>
    );
  }
}

class Child extends React.Component {
  componentDidMount() {
    console.log('componentDidMount');
  }

  componentWillUnmount() {
    console.log('componentWillUnmount');
  }
  
  render() {
   return (
      <div>
       CHILD
      </div>
    );
  }
}

ReactDOM.render(<Parent />, appRoot);
2reactions
Brodzkocommented, Feb 5, 2021

What do you use reparenting for today?

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? 😃

Read more comments on GitHub >

github_iconTop Results From Across the Web

Reparenting is now possible with React | The Startup - Medium
Searches continue on Medium, Dev.to, and other platforms, the only possible solution seems to be the use of the Portals. A Tweet by...
Read more >
Reparenting to Heal the Wounded Inner Child
Reparenting involves learning to give your wounded inner child all the love, respect, and dignity they deserved when you were young.
Read more >
What is Reparenting and How to Begin
Reparenting is the act of giving yourself what you didn't receive as a child. ... Use this Mantra: “What can I give myself...
Read more >
How to Reparent Yourself Using These 5 Powerful Techniques
And will one day allow the same for my children. Journal Prompts. Using journal prompts helped too. I use the journal prompts found...
Read more >
Reparenting Your Inner Child: Ways to Encourage ...
Let yourself communicate in a way that only you can understand and appreciate. By using art, dance, or music therapy, you can allow...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found