javascriptreactjsreact-contextreact-portal

How do React Portals preserve Context from Providers in a different subtree?


So an interesting and amazing property that Portals solve is preserving Context from a Provider even if your component needs to be rendered somewhere else. If you wrap a component subtree with a ContextProvider, any component rendered in that subtree will have access to the context values.

In turn, if you rendered something outside of the subtree, it wouldn't have access to that Context. React Portals solves this though so if that if you wanted to render something outside of the subtree, you can do it from within that same subtree. I think the React docs touch on this a little:

Features like context work exactly the same regardless of whether the child is a portal, as the portal still exists in the React tree regardless of position in the DOM tree.

I guess I'm not conceptualizing how this actually works. How is it that a a React Portal can have access to the Context without requiring to be rendered in the same subtree? It sounds like behind the scenes, Portals are part of the "React Tree"? So there must be some fancy "pass information and then render the portal logic"? To be clear about my question

How exactly do Portals work in preserving access to context values?


Solution

  • I haven't received an answer for quite a while -- I was hoping to dig into React's code but haven't had a chance (hoping to update my answer one day), but in a nutshell, how this works is behind the scenes, React is maintaining it's own component tree (you may have heard to this referred to as the virtual DOM) and within that, the components that are created will still live in the Provider Subtree in the virtual DOM.

    This article talks a little about it here

    Instead of making two calls to ReactDOM.render(), we create two portals and render both under our top-level Provider. ComponentA and ComponentB will be rendered in two different points in the DOM, but they share the same React tree, thanks to portals.