TL;DR => Portals
and Context
solve different purposes, one is to inject DOM at any level and other is to inject props at any level. Context
can mimic Portals
but Portals
AS OF NOW cannot mimic Context
not at least without introducing code smell.
NOTE: Below is based on my understanding of the two concepts, if anyone has further thoughts or corrections on this please feel free to edit the answer.
From what I was able to understand Portals
are, as the name suggests, a door way for you to render components that need not be in the component tree hierarchy. This works like perfectly for Modals
, Popovers
or any component which needs to be stitched at a particular location in the tree.
Context
is to communicate with various sibling and child components without having to pass props all the way down from parent to the intended component. Of course, this is an important feature to have but it remained in the experimental phase probably due to the fact that this can be achieved by event-emitters
and Redux
, MobX
for a centralized state management.
I am assuming that your use case for i18n
would require a lot of communication across components for which you might want to look at this great article
COMPONENT COMMUNICATION
Portals and Context help achieving this kind of communication but there is a difference. Portals can render or inject DOM at any level and Context can inject props at any level in the subcomponent tree.
You can always achieve what Portals
are able to do using Context
but I don't think Portals
can mimic Context
functionality.
EG: Something like this can be done to mimic what Portals
do using Context
. Where as in Portals
AFAIK you can only send DOM Nodes ReactDOM.createPortal(child, container)
. May be there is a way to achieve the functionality but that would surely lead to code smell.
class Parent extends React.Component {
getChildContext() {
return {
renderModal: this.renderModal
}
}
renderModal = (children) => {
this.setState({
open: !this.state.open,
injectableChildren: children
})
}
render() {
this.state.open
?
<div>
{this.state.injectableChildren}
</div>
:
null
// JSX
}
}
class SomeSibling extends React.Component {
static contextTypes = {
renderModal: React.PropTypes.func
}
handleOnClick = (event) => {
this.context.renderModal(renderableChildJSX);
}
renderableChildJSX = () => (
<div>
YAY I AM GETTING RENDERED AT THE ROOT
</div>
)
render() {
return(
<div onClick={this.handleOnClick}>
</div>
)
}
}
In my case, I feared from using Context
despite it's flexibility due to the fact that React
docs always mentioned that it's an experimental feature and warned repeatedly from using this feature full-blown. My guess is that React is looking at stabilising this feature or completely scrape it off the React codebase which is a risk that could go both ways.
CONCLUSION: IMO, Portals
in it's current state and the problem it is trying to resolve is entirely different from what Context
is built for and it is better to use event-emitters
with the only reason that Context
might possibly be deprecated.