aaronhayes / react-use-hubspot-form

Embed HubSpot forms into your React components using hooks! Works with Create React App, Gatsby and other platforms.
https://www.npmjs.com/package/@aaronhayes/react-use-hubspot-form
MIT License
50 stars 17 forks source link

[Bug] Form is never created #25

Closed snelsi closed 3 years ago

snelsi commented 3 years ago

🐛 I'm submitting a Bug report

Summary

If two useHubspotForm hooks are called on the same page, the second form sometimes may never load.

Background

I'm using the useHubspotForm hook with Next.js a couple of times on the same page. It looks like sometimes only 1 form is rendered properly, and others never load.

While inspecting React dev tools, I noticed that script is loaded and there is no error, but formCreated is set to false.

image

I copied the source code locally and tried to console log hook's state to debug the error:

image

It looks like even if loaded prop returns true, window.hbspt can still be undefined. And when the script is actually loaded useEffect with hbspt.forms.create() does not trigger.

image

Cause of the bug

Here's the problematic code:

    // If cachedScripts array already includes src that means another instance ...
    // ... of this hook already loaded this script, so no need to load again.
    if (cachedScripts.includes(src)) {
      setLoaded(true);  // <-- We return true, even though script may be still loading
      setError(false);
    } else {
      cachedScripts.push(src) // <-- We push src to scripts array, even though it's not appended to the document

Possible solution

You use useScript in one place, for loading https://js.hsforms.net/forms/v2.js script. So it may have more sense to move this logic into a separate HubspotProvider component and use React context to sync loaded / error state between all Hubspot forms:

const HubspotContext = React.createContext({ loaded: false, error: false })

export const useHubspotContext = () => React.useContext(HubspotContext)

export const HubspotProvider = ({ children }) => {
  const [loaded, error] = useScript('https://js.hsforms.net/forms/v2.js')

  return <HubspotContext.Provider value={{ loaded, error }}>{children}</HubspotContext.Provider>
}

export const useHubspotForm = (props) => {
  const { loaded, error } = useHubspotContext()
  const [formCreated, setFormCreated] = useState(false)

  useEffect(() => {
    if (typeof window !== 'undefined' && window) {
      const windowWithHubspot = window
      if (loaded && windowWithHubspot.hbspt && !formCreated) {
        windowWithHubspot.hbspt.forms.create(props)
        setFormCreated(true)
      }
    }
  }, [loaded, formCreated, setFormCreated])

  return { loaded, formCreated, error }
}
aaronhayes commented 3 years ago

Interesting. I'm happy to accept PRs for this.

snelsi commented 3 years ago

@aaronhayes Sure, here you go https://github.com/aaronhayes/react-use-hubspot-form/pull/26

aaronhayes commented 3 years ago

That is fantastic! Thank you. Released in version 2.0.1

kb1995 commented 3 years ago

I just noticed this bug while working for a client project and was just about to delve into how to fix it - then I spotted this. Thanks @snelsi !