I would like to use jQuery and some other third party libraries not native to React. How can I use them in my React projects? I read componentDidMount
is a good place to invoke third party libraries.
Unfortunately, I am unable to use the libraries as I keep getting " is not defined" errors even though I have properly linked script tags to those libraries in my index.html file.
Third-party libraries can be integrated with class components, also with functional components using Hooks. According to Dan Abramov, they (React Team in Facebook) have no plans to remove ES6 class syntax support in the future.
We start by creating an empty <script></script> tag in the memory as script and then assign the necessary attributes to its src and the id to identify the script later. Finally, we append the script to our <body></body> tag to actually load this.
You have two options, both demonstrated by a contrived example where I fade out a unordered list using jQuery. There are pros and cons to both approaches, I highlight both, and then provide my choice.
index.html
<head>
...
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
...
</head>
App.jsx
import React, { Component } from "react";
class App extends Component {
componentDidMount() {
// ** following two lines of code do the same thing
// using the first version, however, could potentially cause errors
// see "Referencing unimported libraries when using create-react-app"
$(this.refs.list).fadeOut(); // version 1
window.$(this.refs.list).fadeOut(); // version 2
}
render() {
return (
<ul ref="list">
<li>Item 1</li>
<li>Item 2</li>
</ul>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
Referencing unimported libraries when using create-react-app
** If you are using create-react-app
to scaffold your project, using the first version of code will throw errors. This is because create-react-app
's default syntax linter (eslint) will throw errors during project compilation if you try to reference non-imported code (i.e. you never import $ from "jquery"
since we reference the library in index.html
). So when we referencing jQuery's global $
reference (which is very normal when using jQuery in the browser), we violate the basic principles of building modular JavaScript applications on Node.js. In Node, modules are the way of life and in those modules, we can only reference objects that we explicitly import. Without that explicit mention we technically break convention, hence the complaint from the linter.
Now both you and I know that the $
reference will become available once the application actually runs in the browser. When componentDidMount()
is invoked, view has already mounted to the DOM and your third party library (in our example jQuery) is available to reference. Unfortunately the linter will block your react app from rendering because it thinks you are trying to reference undefined variables. Furthermore, the linter is platform agnostic and has no knowledge that your app is running in the browser (since JavaScript is no longer a browser-only language). This may be annoying but the linter is just doing its job, and, to some degree, it's absolutely right.
To avoid this error there are a few options:
// eslint-disable-next-line
(not preferred)
, or window
(preferred), orThe first option can easily become a hassle if you make a lot of calls to the third party library. If you read up on componentDidMount
, you know that at this point of invocation, you now have access to the window
variable. You can access your library through window
if the library attaches itself to the DOM's global window
object. In our example, jQuery does just that and we can access jQuery's functionality via window.$
npm install <package-name> -S
and import
the library into relevant project files.Terminal
npm i jquery -S
App.jsx
import React, { Component } from "react";
import $ from "jquery";
class App extends Component {
componentDidMount() {
$(this.refs.list).fadeOut();
}
render() {
return (
<ul ref="list">
<li>Item 1</li>
<li>Item 2</li>
</ul>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
What is the right approach?
There are pros and cons of each approach: with first one you have the possibility of using a library that is hosted on a CDN and bank on the network effects and don't need to import third party code into your codebase. With the latter, you can make your code more readable and avoid the linter from blowing up.
For cons, the first approach may require you to add window
to your third party library calls if you're using a linter (and you probably should); in the latter's case, sometimes third party libraries don't have their project code available to install through npm and you must download them manually and manually add them to your project source folder. In that case, using the first approach might make sense so that you don't have to manually import new versions of the library when they're released.
If at the end of all of this, you have failing code:
If you know of other ways of accomplishing third party library integrations into react or find an error in this post, please feel free to edit this answer or add another answer.
The examples in this answer assume the execution environment is a browser, hence the use of window
. If you are building a shell script or using react-native, it would be global
, etc.
I needed to use the third party libraries as well as custom written javascript files inside of a React Component without loading them across other routes.
Kindly note am use a React Hook i.e. useEffect()
thus you need a version of react which supports them.
Below is what worked for me.
import React, { useEffect } from "react";
const Airstrip = props => {
useEffect(() => {
// Now Attach All Third Party Scripts.
let threeJsScript = document.createElement("script");
let orbitJsScript = document.createElement("script");
let guiJsScript = document.createElement("script");
let mainJsScript = document.createElement("script");
// Hook Sources.
threeJsScript.src = `${process.env.PUBLIC_URL}/js/three.js`;
orbitJsScript.src = `${process.env.PUBLIC_URL}/js/orbit.js`;
guiJsScript.src = `${process.env.PUBLIC_URL}/js/gui.js`;
mainJsScript.src = `${process.env.PUBLIC_URL}/js/main.js`;
// Persist order of Loading.
threeJsScript.async = false;
orbitJsScript.async = false;
guiJsScript.async = false;
mainJsScript.async = false;
// Append to index.html
document.body.appendChild(threeJsScript);
document.body.appendChild(orbitJsScript);
document.body.appendChild(guiJsScript);
document.body.appendChild(mainJsScript);
// Do Clean ups
return () => {
document.body.removeChild(threeJsScript);
document.body.removeChild(orbitJsScript);
document.body.removeChild(guiJsScript);
document.body.removeChild(mainJsScript);
};
}, []);
return (
<div id="airstrip">
<canvas
id="canvas"
onClick={() => {
alert("Yeah");
}}
></canvas>
</div>
);
};
export default Airstrip;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With