{"id":14868,"library":"react-async-script","title":"React Async Script Loader","description":"react-async-script is a lightweight React Higher-Order Component (HOC) designed to facilitate the asynchronous loading of external third-party JavaScript scripts within React applications. It is particularly useful for integrating services like Google reCAPTCHA, Google Maps, or other widgets where scripts need to be loaded dynamically without blocking the main thread. The current stable version is 1.2.0, building upon the significant 1.0.0 rewrite that introduced modern React features. The library supports customizing script attributes, automatically registering global callback functions (e.g., for `onload` events), and exposing global variables created by the loaded scripts as props to the wrapped component. It also incorporates React's `forwardRef` for proper ref handling, requiring React version 16.4.1 or higher. While no explicit release cadence is stated, it receives updates to address issues and maintain compatibility with React. Its key differentiator is its focused approach as a simple HOC for script management.","status":"active","version":"1.2.0","language":"javascript","source_language":"en","source_url":"https://github.com/dozoisch/react-async-script","tags":["javascript","react","asynchronous","script-loader"],"install":[{"cmd":"npm install react-async-script","lang":"bash","label":"npm"},{"cmd":"yarn add react-async-script","lang":"bash","label":"yarn"},{"cmd":"pnpm add react-async-script","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Peer dependency for React component usage, specifically for `React.forwardRef` functionality.","package":"react","optional":false}],"imports":[{"note":"The `makeAsyncScriptLoader` HOC is exported as the default export in modern (ESM) environments. Using named import syntax will result in an `undefined` value.","wrong":"import { makeAsyncScriptLoader } from 'react-async-script'; // Incorrectly attempts named import for a default export","symbol":"makeAsyncScriptLoader","correct":"import makeAsyncScriptLoader from 'react-async-script';"},{"note":"For CommonJS environments (e.g., Node.js or older bundlers), the `require` statement directly retrieves the default export. Destructuring it will lead to an `undefined` value or a runtime error.","wrong":"const { makeAsyncScriptLoader } = require('react-async-script'); // Incorrectly destructures a default export in CommonJS","symbol":"makeAsyncScriptLoader (CommonJS)","correct":"const makeAsyncScriptLoader = require('react-async-script');"}],"quickstart":{"code":"import React from 'react';\nimport ReactDOM from 'react-dom';\nimport makeAsyncScriptLoader from 'react-async-script';\n\n// A placeholder component that would typically consume the loaded script\nclass MyComponentNeedingScript extends React.Component {\n  componentDidUpdate(prevProps) {\n    // Access the global object exposed by the loaded script via props\n    if (!prevProps.googleMaps && this.props.googleMaps) {\n      console.log('Google Maps API is available:', this.props.googleMaps);\n      // Example: Initialize a map once the API is loaded\n      // new this.props.googleMaps.Map(document.getElementById('map'), { center: {lat: -34, lng: 151}, zoom: 8 });\n    }\n  }\n  render() {\n    return (\n      <div>\n        <p>Loading external script...</p>\n        {/* You might render a placeholder or a loading spinner here */}\n        <div id=\"map\" style={{ width: '100%', height: '300px' }}></div>\n      </div>\n    );\n  }\n}\n\n// Define the script URL, callback name, and the global object name\nconst SCRIPT_URL = `https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap`;\nconst CALLBACK_NAME = 'initMap';\nconst GLOBAL_NAME = 'googleMaps'; // The global object set by the script (e.g., window.googleMaps)\n\n// Wrap your component with the HOC\nconst GoogleMapsLoader = makeAsyncScriptLoader(SCRIPT_URL, {\n  callbackName: CALLBACK_NAME,\n  globalName: GLOBAL_NAME,\n  removeOnUnmount: true, // Optional: remove script tag when component unmounts\n})(MyComponentNeedingScript);\n\nclass App extends React.Component {\n  constructor(props) {\n    super(props);\n    this._myRef = React.createRef();\n  }\n\n  componentDidMount() {\n    console.log(\"Ref to MyComponentNeedingScript instance:\", this._myRef.current);\n  }\n\n  handleScriptLoad = () => {\n    console.log(\"External Google Maps script has finished loading!\");\n    // Any post-load actions can be performed here\n  };\n\n  render() {\n    return (\n      <div>\n        <h1>React Async Script Loader with Google Maps</h1>\n        <GoogleMapsLoader ref={this._myRef} asyncScriptOnLoad={this.handleScriptLoad} />\n      </div>\n    );\n  }\n}\n\n// Ensure a root element exists for React to render into\nconst rootElement = document.getElementById('root');\nif (!rootElement) {\n  const div = document.createElement('div');\n  div.id = 'root';\n  document.body.appendChild(div);\n}\n\nReactDOM.render(<App />, rootElement);\n\n// Simulate the global callback function that the Google Maps API calls\n// This must be a global function for the script to find it\nwindow[CALLBACK_NAME] = () => {\n  console.log(`Global callback '${CALLBACK_NAME}' executed.`);\n  // For Google Maps, the 'google.maps' global becomes available after this.\n  // The HOC will pick this up and pass 'googleMaps' as a prop.\n};\n","lang":"javascript","description":"Demonstrates how to use `makeAsyncScriptLoader` to load an external script (e.g., Google Maps API), handle its `onload` callback, access global variables exposed by the script, and utilize `forwardRef` with the wrapped component. Replace `YOUR_API_KEY` with an actual key."},"warnings":[{"fix":"Review the official migration guide for 1.0.0 on the GitHub repository. Update your `makeAsyncScriptLoader` calls to reflect the new `makeAsyncScriptLoader(getScriptUrl, options)(Component)` signature and adjust option names accordingly.","message":"Version 1.0.0 introduced significant breaking changes, altering the HOC's API signature. The wrapped component is now passed as a second function call, the `removeOnMount` option was renamed to `removeOnUnmount` (fixing a typo), and the `exposeFuncs` option was removed entirely as its functionality is now automatic.","severity":"breaking","affected_versions":">=1.0.0"},{"fix":"Ensure your project's `react` and `react-dom` peer dependencies are updated to `^16.4.1` or a more recent compatible version.","message":"This library relies on React's `forwardRef` functionality internally, which requires React version `16.4.1` or higher. Using older versions of React will lead to runtime errors related to `ref` handling.","severity":"gotcha","affected_versions":"<16.4.1"},{"fix":"In your wrapped component, always check if the `globalName` prop (e.g., `this.props.googleMaps`) is truthy before attempting to use it. A common pattern is to perform actions in `componentDidUpdate` when the prop transitions from `undefined` to a defined value.","message":"When using the `globalName` option, the library passes `window[globalName]` as a prop to your wrapped component. If the external script has not yet initialized or set this global object when your component first renders, the prop will be `undefined`.","severity":"gotcha","affected_versions":"*"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Change your import statement from `import { makeAsyncScriptLoader } from 'react-async-script';` to `import makeAsyncScriptLoader from 'react-async-script';`.","cause":"Attempting to import `makeAsyncScriptLoader` as a named export from `react-async-script` in an ESM context, but it is a default export.","error":"TypeError: (0, react_async_script__WEBPACK_IMPORTED_MODULE_0__.makeAsyncScriptLoader) is not a function"},{"fix":"Verify that your `react` and `react-dom` packages are at least version `16.4.1`. If you are trying to attach a `ref` to your own functional component that is then wrapped by the HOC, ensure that component itself uses `React.forwardRef`.","cause":"This error typically indicates an incompatibility with the React version being used, as `react-async-script` relies on `forwardRef` introduced in React 16.4.1, or an issue with how `ref` is being handled in your own components if you're attempting to forward it further.","error":"Error: Invariant Violation: The `ref` prop is only available for DOM components or using React.forwardRef(). Check the render method of `YourWrappedComponent`."}],"ecosystem":"npm"}