I am trying to create a component that renders the Buy Me A Coffee widget in some routes of my react single page application. This is my component so far:
class BuyMeACoffee extends React.Component { componentDidMount () { const script = document.createElement("script",); script.setAttribute('data-name','BMC-Widget') script.src = "https://cdnjs.buymeacoffee.com/1.0.0/widget.prod.min.js" script.setAttribute('data-id', 'boulderproblems'); script.setAttribute('data-description', 'Thank you for your support!'); script.setAttribute('data-message', 'This web is free to use. Do you want to help supporting it?'); script.setAttribute('data-color',"#FF5F5F") script.setAttribute('data-position','right') script.setAttribute('data-x_margin','18') script.setAttribute('data-y-margin','18') script.async = true document.head.appendChild(script) } render(){ return(null) } }
When I inspect the page with the developer tools, the tag is at the end of the head section and everything seems correct but the widget doesn’t show in the page.
Note: If I copy the script code in the head section of the index.html page:
<script data-name="BMC-Widget" src="https://cdnjs.buymeacoffee.com/1.0.0/widget.prod.min.js" data-id="boulderproblems" data-description="Thank you for your support!" data-message="This web is free to use. Do you want to help supporting it?" data-color="#FF5F5F" data-position="right" data-x_margin="18" data-y-margin="18"></script>
then it works perfectly. The problem is that in this case, the widget is shown for all routes. I have also tried react-helmet without success.
Advertisement
Answer
I finnally got it working. I post my solution here in case it is useful for someone. Not sure if it is the most elegant but it works. I slightly modified the original component so the script and widget is removed when the component is unmounted. Here is the component now:
class BuyMeACoffe extends React.Component { constructor(props){ super(props) let script = document.createElement("script"); script.setAttribute('data-name','BMC-Widget') script.src = "https://cdnjs.buymeacoffee.com/1.0.0/widget.prod.min.js" script.setAttribute('data-id', 'boulderproblems'); script.setAttribute('data-description', 'Thank you for your support!'); script.setAttribute('data-message', 'This web is free to use. Do you want to help supporting it?'); script.setAttribute('data-color',"#FF5F5F") script.setAttribute('data-position','right') script.setAttribute('data-x_margin','18') script.setAttribute('data-y-margin','18') script.async = true //Call window on load to show the image script.onload=function(){ var evt = document.createEvent('Event'); evt.initEvent('DOMContentLoaded', false, false); window.dispatchEvent(evt); } this.script=script } componentDidMount () { document.head.appendChild(this.script) } componentWillUnmount(){ document.head.removeChild(this.script); document.body.removeChild(document.getElementById("bmc-wbtn")) } render(){ return(null) } }
Basically, after reading the buymeacoffee script I realized that they load the widget when the window is DOMContentLoaded event is fired. What I do is to fire this event manually after I insert the script.
Note: After doing this, I had to add a couple of styles because the widget was showing out of the screen. Maybe it was because of my layout. Anyway, here they are in case they you need them:
#bmc-wbtn{ bottom: 15px; } #bmc-wbtn + div{ bottom:15px; }