Thiago Régis
Thiago Régis

Reputation: 123

Embed Pinterest widget in React

I wrote the following component to embed a Pinterest widget in my React app:

import React, { Component } from 'react'

class PinterestWidget extends Component {
  componentWillMount() {
    const script = document.createElement('script')

    script.async = true
    script.type = 'text/javascript'
    script['data-pin-build'] = 'doBuild'
    script.src = '//assets.pinterest.com/js/pinit.js'
    document.body.appendChild(script)
  }

  render() {
    const { url } = this.props

    return (
      <a data-pin-do="embedPin" data-pin-build="doBuild" href={url}>
        {url}
      </a>
    )
  }
}

export default PinterestWidget

It works fine when the component mount the first time.

But when I navigate to another route and go back to this page, it doesn't render the widget anymore.

I tried to place the script in componentDidUpdate, but no success.

PS: I searched for a component but the only one I found is react-pinterest which is not maintained for 2 years — and doesn't work in my app.

Can anybody help me?

Upvotes: 3

Views: 1893

Answers (2)

GWorking
GWorking

Reputation: 4341

In my case, using the answer of @n33kos it works with useEffect and so far every time (without checking whether it has appended the script or not). Here the <a> link to pinterest exist in a markdown file that is injected as html

  useEffect(() => {
    const script = document.createElement('script')
    script.async = true
    script.type = 'text/javascript'
    script.dataset.pinBuild = 'doBuild'
    script.src = '//assets.pinterest.com/js/pinit.js'
    document.body.appendChild(script)
    if (window.doBuild) window.doBuild()
  }, []) // only run once

Upvotes: 0

n33kos
n33kos

Reputation: 76

I found myself in the exact same position today. After wrestling with forks of that same react-pinterest npm package I found a solution in this issue https://github.com/pinterest/widgets/issues/13.

It looks like you already got close by adding the data-pin-build="doBuild" data attribute but you aren't calling doBuild() when the user returns to the component after hitting a different route. Adding the data attribute instructs pinit.js to add doBuild() to the global scope but doesn't automatically call the function when you remount the component.

Try replacing your componentWillMount function with something like this:

componentDidMount() {
  if (!window.doBuild) {
    this.preloadWidgetScript();
  } else {
    window.doBuild();
  }
}

preloadWidgetScript = () => {
  const script = document.createElement('script');
  script.async = true;
  script.dataset.pinBuild = 'doBuild';
  script.src = '//assets.pinterest.com/js/pinit.js';
  document.body.appendChild(script);
}

One other thing to note is the change from componentWillMount to componentDidMount, this is necessary to ensure the embed link is rendered before running doBuild().

Upvotes: 2

Related Questions