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.
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 asdata-
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 onwindow
for you.globalName
: string : Can provide the name of the global that the script attaches towindow
. Async-script will pass this as a prop to the wrapped component. (props[globalName] = window[globalName]
)removeOnUnmount
: boolean default=false : If set totrue
removes the script tag when component unmounts.scriptId
: string : If set, it adds the following id on the script tag.
const AsyncScriptComponent = makeAsyncScriptLoader(URL)(Component);
// ---
<AsyncScriptComponent asyncScriptOnLoad={callAfterScriptLoads} />
asyncScriptOnLoad
: function : called after script finishes loading. usingscript.onload
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} />)}
}
At least [email protected]
is required due to forwardRef
usage internally.
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
);