136 lines
4.9 KiB
Markdown
136 lines
4.9 KiB
Markdown
# React Async Script Loader
|
|
|
|
[![Build Status][travis.img]][travis.url] [![npm version][npm.img]][npm.url] [![npm downloads][npm.dl.img]][npm.dl.url] [![Dependencies][deps.img]][deps.url]
|
|
|
|
**NOTE* - These are the docs for the upcoming `1.0.0` release - for `v0.11.1` documention go to tag here: [0.11.1](https://github.com/dozoisch/react-async-script/tree/v0.11.1)
|
|
|
|
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
|
|
```js
|
|
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:
|
|
```js
|
|
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 `React@16.4.1` is required due to `forwardRef` usage internally.
|
|
|
|
|
|
### Example
|
|
|
|
See https://github.com/dozoisch/react-google-recaptcha
|
|
|
|
```js
|
|
// 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
|
|
);
|
|
```
|
|
|
|
## Migration to 1.0
|
|
|
|
- Component is now passed as a second function call
|
|
- removeOnMount is now removeOnUnmount (typo fixed!)
|
|
- exposeFuncs is no longer needed as it's done automatically!
|
|
|
|
```diff
|
|
-export default makeAsyncScriptLoader(ReCAPTCHA, getURL, {
|
|
+export default makeAsyncScriptLoader(getURL, {
|
|
callbackName,
|
|
globalName,
|
|
- removeOnMount: initialOptions.removeOnMount || false,
|
|
+ removeOnUnmount: initialOptions.removeOnUnmount || false,
|
|
- exposeFuncs: ["getValue", "getWidgetId", "reset", "execute"],
|
|
-});
|
|
+})(ReCAPTCHA);
|
|
```
|
|
|
|
|
|
## Notes
|
|
|
|
Pre `1.0.0` and - `React < React@16.4.1` support details in [0.11.1](https://github.com/dozoisch/react-async-script/tree/v0.11.1).
|
|
|
|
---
|
|
|
|
[travis.img]: https://travis-ci.org/dozoisch/react-async-script.svg?branch=master
|
|
[travis.url]: https://travis-ci.org/dozoisch/react-async-script
|
|
[npm.img]: https://badge.fury.io/js/react-async-script.svg
|
|
[npm.url]: http://badge.fury.io/js/react-async-script
|
|
[npm.dl.img]: https://img.shields.io/npm/dm/react-async-script.svg
|
|
[npm.dl.url]: https://www.npmjs.com/package/react-async-script
|
|
[deps.img]: https://david-dm.org/dozoisch/react-async-script.svg
|
|
[deps.url]: https://david-dm.org/dozoisch/react-async-script
|