Created
November 28, 2018 20:51
-
-
Save unel/5bc6ef23197dbcbe9cea65242b1b36b7 to your computer and use it in GitHub Desktop.
portals
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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