Last active
October 17, 2018 09:25
-
-
Save everdimension/048a2d9b3bc49a8224b0850e98b54dce to your computer and use it in GitHub Desktop.
Sample code showing a "toaster" architecture
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 React from 'react'; | |
import { ToasterContainer, Toaster } from '../'; | |
import { Notification } from '../../../Notification'; | |
/** this instance should be imported by those components that need it */ | |
const toaster = new Toaster(); | |
let id = 0; | |
export function ToasterExample() { | |
return ( | |
<div> | |
<button | |
onClick={() => | |
toaster.show({ | |
id: id++, | |
payload: { | |
message: 'Block has been moved', | |
}, | |
}) | |
} | |
> | |
show toast | |
</button> | |
{/** | |
* ToasterContainer should probably be rendered closer | |
* to the root of the app | |
*/} | |
<ToasterContainer | |
style={{ | |
position: 'absolute', | |
right: 0, | |
bottom: 0, | |
width: 400, | |
}} | |
toaster={toaster} | |
renderToast={({ toast, handleClose }) => ( | |
<Notification | |
message={toast.payload.message} | |
onClose={() => handleClose(toast)} | |
/> | |
)} | |
/> | |
</div> | |
); | |
} |
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
class Toaster { | |
constructor() { | |
this.listeners = []; | |
this.id = 0; | |
} | |
subscribe(listener) { | |
this.listeners.push(listener); | |
return () => { | |
this.listeners = this.listeners.filter(l => l !== listener); | |
}; | |
} | |
show(toastConfig) { | |
Object.assign(toastConfig, { timestamp: Date.now() }); | |
if (!toastConfig.id) { | |
Object.assign(toastConfig, { id: this.id }); | |
this.id += 1; | |
} | |
this.listeners.forEach(l => { | |
l(toastConfig); | |
}); | |
} | |
} | |
export { Toaster }; |
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 React from 'react'; | |
import PropTypes from 'prop-types'; | |
import s from './ToasterContainer.css'; | |
const propTypes = { | |
toaster: PropTypes.shape({ | |
subscribe: PropTypes.func, | |
}).isRequired, | |
renderToast: PropTypes.func.isRequired, | |
}; | |
class ToasterContainer extends React.Component { | |
constructor() { | |
super(); | |
this.state = {}; | |
this.timers = {}; | |
this.handleCloseToast = this.handleCloseToast.bind(this); | |
} | |
componentDidMount() { | |
this.unsubscribe = this.props.toaster.subscribe(toast => { | |
this.setState({ | |
[toast.id]: toast, | |
}); | |
clearTimeout(this.timers[toast.id]); | |
delete this.timers[toast.id]; | |
this.timers[toast.id] = setTimeout(() => { | |
this.setState({ | |
[toast.id]: null, | |
}); | |
delete this.timers[toast.id]; | |
}, 5000); | |
}); | |
} | |
componentWillUnmount() { | |
this.unsubscribe(); | |
Object.values(this.timers).forEach(clearTimeout); | |
} | |
handleCloseToast(toast) { | |
this.setState({ | |
[toast.id]: null, | |
}); | |
delete this.timers[toast.id]; | |
} | |
render() { | |
const { renderToast, toaster, ...restProps } = this.props; | |
/** Render toasts in reverse-chronological order */ | |
/** | |
* NOTE: | |
* Order of object values is guaranteed to be the same | |
* and in the order that the values were added | |
*/ | |
const displayToasts = Object.values(this.state) | |
.filter(Boolean) | |
.sort((a, b) => b.timestamp - a.timestamp); | |
return ( | |
<div {...restProps}> | |
<div> | |
<div> | |
{displayToasts.map(toast => ( | |
<div key={toast.id} className={s.Item}> | |
{this.props.renderToast({ | |
toast, | |
handleClose: this.handleCloseToast, | |
})} | |
</div> | |
))} | |
</div> | |
</div> | |
</div> | |
); | |
} | |
} | |
ToasterContainer.propTypes = propTypes; | |
export { ToasterContainer }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment