A Work in Progress

developer's blog by Wei
lots of work in progress notes
TimelineCredits

Portal into a React Component

October 22, 2019

Problem

I ran into this problem when I was working with React Portals.

In its official demo, you render into a DOM element "on the ground".

<html>
  <body>
    <div id="app-root"></div>
    <div id="modal-root"></div>
  </body>
</html>

And when you render, you render into that node. (This is an over simplification, the original demo creates another DOM node, and append it into #modal-root. But the idea is similar enough to make the point.)

render() {
  return ReactDOM.createPortal(
    this.props.children,
    document.getElementById('modal-root')
  );
}

Now, what happens if the target element for the portal to render into is not hard coded in the HTML, but is another React component instead, and it may or may not have been mounted, by the time the portal tries to render into it?

Approach

In a few words, the approach is that

  • use refs instead of DOM selectors to find the slots
  • maintain refs to all possible slots in an object and put the object & setter (dispatcher) in context

I have a demo in this CodeSandbox and below is a little illustration:

There is an older but similar implementation of this using class components. It's open sourced as a library React Slots Fill.

Implementation notes

This section is not yet written, some bullet points:

  • refs allow access to DOM nodes "on the ground"
  • Mutating the .current property doesn’t cause a re-render. Since we need to run some code when React attaches or detaches a ref to a DOM node, we need to use a callback ref instead
  • use a reducer for state updates because useReducer is the cheat mode of hooks, this solves a valid problem whereby mounting two pairs of slots-portals would result in the second mounted component overwriting the first one since the second setState call is closed with its own render

Thoughts

This section is also not yet written, some bullet points:

  • refs are "escape hatch" so not sure if this whole thing is necessarily a good idea
  • React used to have "string ref", and why it's advised against
  • also not necessarily a good idea to (systematically) put stateful variables with complex update schemes in context

Relevant links