Skip to content

A React composition mixin for loading 3rd party scripts asynchronously

License

Notifications You must be signed in to change notification settings

dozoisch/react-async-script

Repository files navigation

React Async Script Loader

Build Status npm version npm downloads

A React HOC for loading 3rd party scripts asynchronously. This HOC allows you to wrap a component that needs 3rd party resources, like reCAPTCHA or Google Maps, and have them load the script asynchronously.

Usage

Async Script HOC api

makeAsyncScriptLoader(getScriptUrl, options)(Component)

  • Component: The Component to wrap.
  • getScriptUrl: string or function that returns the full URL of the script tag.
  • options (optional):
    • attributes: object : If the script needs attributes (such as data- attributes), then provide them as key/value pairs of strings and they will be added to the generated script tag.
    • callbackName: string : If the script needs to call a global function when finished loading (for example: recaptcha/api.js?onload=callbackName). Please provide the callback name here and it will be autoregistered on window for you.
    • globalName: string : Can provide the name of the global that the script attaches to window. Async-script will pass this as a prop to the wrapped component. (props[globalName] = window[globalName])
    • removeOnUnmount: boolean default=false : If set to true removes the script tag when component unmounts.
    • scriptId: string : If set, it adds the following id on the script tag.

HOC Component props

const AsyncScriptComponent = makeAsyncScriptLoader(URL)(Component);
// ---
<AsyncScriptComponent asyncScriptOnLoad={callAfterScriptLoads} />
  • asyncScriptOnLoad: function : called after script finishes loading. using script.onload

Ref and forwardRef

react-async-script uses react's forwardRef method to pass along the ref applied to the wrapped component.

If you pass a ref prop you'll have access to your wrapped components instance. See the tests for detailed example.

Simple Example:

const AsyncHoc = makeAsyncScriptLoader(URL)(ComponentNeedsScript);

class DisplayComponent extends React.Component {
  constructor(props) {
    super(props);
    this._internalRef = React.createRef();
  }
  componentDidMount() {
    console.log("ComponentNeedsScript's Instance -", this._internalRef.current);
  }
  render() { return (<AsyncHoc ref={this._internalRef} />)}
}
Notes on Requirements

At least [email protected] is required due to forwardRef usage internally.

Example

See https://github.com/dozoisch/react-google-recaptcha

// recaptcha.js
export class ReCAPTCHA extends React.Component {
  componentDidUpdate(prevProps) {
    // recaptcha has loaded via async script
    if (!prevProps.grecaptcha && this.props.grecaptcha) {
      this.props.grecaptcha.render(this._container)
    }
  }
  render() { return (
    <div ref={(r) => this._container = r} />)
  }
}

// recaptcha-wrapper.js
import makeAsyncScriptLoader from "react-async-script";
import { ReCAPTCHA } from "./recaptcha";

const callbackName = "onloadcallback";
const URL = `https://www.google.com/recaptcha/api.js?onload=${callbackName}&render=explicit`;
// the name of the global that recaptcha/api.js sets on window ie: window.grecaptcha
const globalName = "grecaptcha";

export default makeAsyncScriptLoader(URL, {
  callbackName: callbackName,
  globalName: globalName,
})(ReCAPTCHA);

// main.js
import ReCAPTCHAWrapper from "./recaptcha-wrapper.js"

const onLoad = () => console.log("script loaded")

React.render(
  <ReCAPTCHAWrapper asyncScriptOnLoad={onLoad} />,
  document.body
);