Skip to content

Instantly share code, notes, and snippets.

@unel
Created November 28, 2018 20:51
Show Gist options
  • Save unel/5bc6ef23197dbcbe9cea65242b1b36b7 to your computer and use it in GitHub Desktop.
Save unel/5bc6ef23197dbcbe9cea65242b1b36b7 to your computer and use it in GitHub Desktop.
portals
import * as React from 'react';
class App extends React.Component{
portals = createPortals();
render() {
const {PortalIn, PortalOut} = this.portals;
return (
<PortalOut name='dialogs' />
....
....
<PortalIn name='dialogs'>
<div>hello, world!!!</div>
</PortalIn>
);
}
}
export default App;
import * as React from 'react';
import { get, set } from 'lodash';
class PortalsContent {
private subscribers: any[];
private content: any;
constructor() {
this.content = {};
this.subscribers = [];
}
addSubscriber(cb) {
this.subscribers.push(cb);
}
notifySubscribers(data) {
this.subscribers.forEach(cb => cb(data));
}
removeSubscriber(cb) {
const index = this.subscribers.findIndex(cb);
if (index !== -1) {
this.subscribers.splice(index, 1);
}
}
setPortalContent(name, content) {
set(this.content, name, content);
this.notifySubscribers({ name, content });
}
removePortalContent(name) {
delete this.content[name];
this.notifySubscribers({ name, content: null });
}
getPortalContent(name) {
return get(this.content, name, null);
}
}
function createPortals() {
const portalsContent = new PortalsContent();
/* tslint:disable max-classes-per-file */
/* because we need 2 different components with same context */
class PortalOut extends React.Component<{ name: string }, any> {
state = {
content: portalsContent.getPortalContent(this.props.name)
};
private onPortalsChanged = (data) => {
if (data.name === this.props.name) {
this.setState({
content: data.content,
});
}
};
componentWillMount() {
portalsContent.addSubscriber(this.onPortalsChanged);
}
componentWillUnmount() {
portalsContent.removeSubscriber(this.onPortalsChanged);
}
render() {
return this.state.content;
}
}
class PortalIn extends React.Component<{ name: string }, any> {
componentWillMount() {
portalsContent.setPortalContent(this.props.name, this.props.children);
}
componentWillReceiveProps(newProps) {
if (this.props.children) {
portalsContent.setPortalContent(this.props.name, this.props.children);
} else {
portalsContent.removePortalContent(this.props.name);
}
}
componentWillUnmount() {
portalsContent.removePortalContent(this.props.name);
}
render() {
return null;
}
}
/* tslint:enable max-classes-per-file */
return {PortalIn, PortalOut};
}
export {createPortals};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment