Loading Scripts on specific component (Route) in React - javascript

Is it possible to run html scripts in a specific React component only, instead of directly in index.html. The script loads a third party barcode scanner, which is only being used in one component, and therefore I want to avoid loading it for every component as this will slow the whole app down.
The npm module can be found here: https://www.npmjs.com/package/dynamsoft-javascript-barcode but there is no documentation on how to import it, only to include it like this:
<script src="https://cdn.jsdelivr.net/npm/dynamsoft-javascript-barcode#7.2.2-v2/dist/dbr.js" data-productKeys="LICENSE-KEY"></script>
<script>
let barcodeScanner = null;
Dynamsoft.BarcodeScanner.createInstance({
onFrameRead: results => {console.log(results);},
onUnduplicatedRead: (txt, result) => {alert(txt);}
}).then(scanner => {
barcodeScanner = scanner;
barcodeScanner.show();
});
</script>

Here is the React sample provided by Dynamsoft GitHub repository: https://github.com/dynamsoft-dbr/javascript-barcode/tree/master/example/web/react
You can check out Dynamsoft.js and HelloWorld.js to see how to import and use the module:
import Dynamsoft from "dynamsoft-javascript-barcode";
Dynamsoft.BarcodeReader.engineResourcePath = "https://cdn.jsdelivr.net/npm/dynamsoft-javascript-barcode#7.3.0-v1/dist/";
// Please visit https://www.dynamsoft.com/CustomerPortal/Portal/TrialLicense.aspx to get a trial license
Dynamsoft.BarcodeReader.productKeys = "PRODUCT-KEYS";
// Dynamsoft.BarcodeReader._bUseFullFeature = true; // Control of loading min wasm or full wasm.
export default Dynamsoft;
import Dynamsoft from "../Dynamsoft";
import React from 'react';
class HelloWorld extends React.Component {
...
let reader = this.reader = this.reader || await Dynamsoft.BarcodeReader.createInstance();
...
}
Note: This sample uses 7.3.0-v1. 7.2.2-v2 does not support this usage.

I haven't tried this code but I have done some code like this.You can add script tag like this:
class YourComponent extends React.Component {
loadScript() {
let script = document.createElement("script");
script.src = "https://cdn.jsdelivr.net/npm/dynamsoft-javascript-barcode#7.2.2-v2/dist/dbr.js";
script.setAttribute("data-productKeys","LICENSE-KEY");
script.type = "text/javascript";
document.head.append(script);
}
componentWillMount() {
if(!YourComponent.bScriptLoaded){
this.loadScript();
YourComponent.bScriptLoaded = true;
}
}
}
This will add script tag in head tag and.And after that you can run your code in component.

Related

Running js script from public folder with <script> tag works, but not importing from local file

When I place js script into "public" folder then import this way into script tag script.src = "/scoper.js";, js script runs fine. But when I move that js script into "src" folder then directly import it, script runs but not properly. So what is the difference when running js script from <script src="..."> and running from import { scoper } from "./scoper.js";?https://codesandbox.io/s/stylesheet-scoping-b0k9pp?file=/src/App.js:65-102
When script runs successfully, "Hello World" text should be red color.
App.js
import React, { useEffect } from "react";
import "./styles.css";
import { scoper } from "./scoper.js"; // this doesn't work
export default function App() {
useEffect(() => {
const script = document.createElement("script");
// script.src = "/scoper.js"; //this works
script.async = true;
document.body.appendChild(script);
let style = document.createElement("style");
style.setAttribute("scoped", "");
style.innerHTML =
".Puma {" +
"color: purple;" +
"font-size: 50px;" +
"text-align: left;" +
"}";
let main = document.getElementById("raptors");
main.appendChild(style);
return () => {
document.body.removeChild(script);
};
}, []);
return (
<>
<div id="lakers" className="Puma">
<div>Hello World!</div>
</div>
<div id="raptors" className="Puma">
<h1>Raptors win!</h1>
</div>
</>
);
}
With import { scoper } from "./scoper.js"; the script is imported and executed when the file App.js is executed the first time, that is the time when e.g. function App() { ... is defined, but before App() gets executed, and before any components are rendered.
useEffect(() => { ... is executed after the component is rendered. So at the time the imported script is executed, the DOM elements rendered by React are available.
Generally, you should not execute the script inside a module immediately when it is imported, because that will always be confusing (there are exceptions, of course). Instead you should export an object or function, so that the importing file can choose when to call it. In case the importing file wants to execute the imported function immediately, it still can do that.

Cannot appendChild to a custom web component

I have a web-component at root level. The simplified version of which is shown below:
class AppLayout {
constructor() {
super();
this.noShadow = true;
}
connectedCallback() {
super.connectedCallback();
this.render();
this.insertAdjacentHTML("afterbegin", this.navigation);
}
render() {
this.innerHTML = this.template;
}
get template() {
return `
<h1>Hello</h1>
`;
}
navigation = `
<script type="module">
import './components/nav-bar.js'
</script>
`;
}
customElements.define('app-layout', AppLayout);
I want to load a script after this component loads. The script creates html for navigation and tries to add it to the app-layout element shown above. However, even though, it does find the app-layout element, it is unable to append the navBar element. It is, however, able to append the navBar to the body of the html. Any ideas what I'm missing.
const navLinks =
`<ul>
<li>Some</li>
<li>Links</li>
</ul>
`;
const navBar = document.createElement('nav');
navBar.innerHTML = navLinks;
const appLayout = document.querySelector('app-layout'); // works with 'body' but not with 'appLayout'
console.log(appLayout); // Logs correct element
appLayout.appendChild(navBar);
I know that what I'm trying to do here (loading a script inside a web component) is not ideal, however, I would like to still understand why the above doesn't work.
using innerHTML or in your case insertAdjacentHTML to add <script> tags to the document doesn't work because browsers historically try to prevent potential cross site script attacks (https://www.w3.org/TR/2008/WD-html5-20080610/dom.html#innerhtml0)
What you could do is something like:
const s = document.createElement("script");
s.type = "module";
s.innerText = `import './components/nav-bar.js'`;
this.append(s);
// or simply directly without the script: `import('./comp..')` if it is really your only js in the script tag.

How to pass often used ("global") variables in ES-6 modules?

I can't create arhitecture for js-code for site.
There are 2 versions of site: mobile and desktop. I want to build separate js-bundle for every version: mobile.js and desktop.js.
Every bundle can include common js-modules, for example form.js (form exists on every site version). But there some uniq elements: desktop has Header and need header.js, mobile has no Header, but has Topbar and need topbar.js.
Bundle for mobile (mobile.js) includes form.js + header.js
Bundle for desktop (desktop.js) includes form.js + topbar.js
Imagine that we need to show form when click on Header(or Topbar).
Our folder structure:
--common/
----form.js
--desktop/
----header.js
--mobile/
----topbar.js
--entryDesktop.js
--entryMobile.js
.
//--- entryDesktop.js
import Form from './common/form.js';
import Header from './desktop/header.js';
new Form(document.querySelector('.form'));
new Header(document.querySelector('.header'));
.
//--- entryMobile.js
import Form from './common/form.js';
import Header from './mobile/topbar.js';
new Form(document.querySelector('.form'));
new Header(document.querySelector('.header'));
.
//--- form.js
export default class Form{
constructor(elem) {
this.elem = elem;
}
show() {
this.elem.classList.remove('form_hidden');
}
}
Actually, modules header.js and topbar.js are very different, have different properties and methods, BUT they have one common action - they can open Form when click on Header (or Topbar)
export default class Header{
constructor(elem) {
this.elem = elem;
...
this.elem.addEventListener('click', () => {
form.show();
})
}
}
.
export default class Topbar{
constructor(elem) {
this.elem = elem;
...
this.elem.addEventListener('click', () => {
form.show();
})
}
}
The main question is how to pass "form" in Header-module (and Topbar-module)?
I can imagine 2 variants
Through window global object.
window.form = new Form(document.querySelector('.form'));```
```//---topbar.js:
this.elem.addEventListener('click', () => {
window.form.show();
})```
BUT then our variables are not isolated, we or third-party scripts can change it occasionally.
Pass "form" as parametr in Class
const form = new Form(document.querySelector('.form'))
new Header(document.querySelector('.topbar'), form);```
```//---header.js:
export default class Header{
constructor(elem, form) {
this.elem = elem;
this.form = form;
this.elem.addEventListener('click', () => {
this.form.show();
})
}
}```
BUT if i need Form in 20 modules - i should pass it in every.
If 1st module imports 2nd module that imports 3d module, and I need Form in 3d module - I need to pass it through All this modules. It looks like hell. Or not?
What is the best way to pass often used variables in specific module?

Access React DOM Element from external script

I am trying to get access to a React DOM element 'id' from an external script file. I believe my script is being imported correctly as console.log('test') from the file is working, though console.log(myDiv) returns null.
How can I achieve this in React?
// COMPONENT
import './../data/script.ts';
render() {
return (
<div id='targetDiv'>
<p>{This will be populated from my external script file...}</p>
</div>
);
}
// SCRIPT
var myDiv = document.getElementById('targetDiv');
console.log(myDiv);
To fix the issue I needed to import my external script as a function, and then call the function after the component mounted:
// COMPONENT
import { myScript } from './../data/script';
componentDidMount() {
{
myScript();
}
}
render() {
return (
<div id='targetDiv'>
{My script now renders correctly inside the div}
</div>
);
}
// SCRIPT
var myDiv = document.getElementById('targetDiv');
const d = document.createElement('p');
myDiv.appendChild(d);

How do I add a custom script to React component?

Long story short: I'm trying to add a front-end app to my portfolio site that uses React. I would like to integrate the app into the component as it renders. What I have setup right now is:
React component:
class Giphy extends Component {
constructor(props) {
super(props);
this.state = {src: 1}
this.handleClick = this.handleClick.bind(this);
}
handleClick(event) {
this.setState({src: event.target.value})
}
componentDidMount() {
const script = document.createElement("script");
script.type = "text/javascript";
script.src = "/scripts/giphyLogic.js";
document.body.appendChild(script);
}
...and a bunch of stuff in the render() method that doesn't matter
the script that I want to load involves a bunch of jQuery and simple JS stuff.
function displayButtons() {
$("#buttons").empty();
for (i=0; i<buttonArray.length; i++){
var a = $("<button type='button' class='btn btn-info'>");
var btnID = buttonArray[i].replace(/\s+/g, "+")
a.attr("id", btnID);
a.text(buttonArray[i]);
$("#buttons").append(a);
}
}
$("#addButton").on("click", function() {
var newButton = $(".form-control").val();
buttonArray.push(newButton);
displayButtons();
})
function displayGIFs() {
$(".btn-info").on("click", function() {
$("#resultsContainer").empty();
var subject = $(this).attr("id");
var giphyURL = "http://api.giphy.com/v1/gifs/search?q=" + subject + "&api_key=dc6zaTOxFJmzC";
$.ajax({ url: giphyURL, method: "GET"}).done(function(res) {
for (t=0; t<25; t++) {
var rating = res.data[t].rating;
var image = $("<img>");
var imgURLmoving = res.data[t].images.fixed_height.url;
var imgURLstill = res.data[t].images.fixed_height_still.url;
image.attr("src", imgURLstill);
image.attr("data-still", imgURLstill);
image.attr("data-moving", imgURLmoving);
image.attr("data-state", "still")
image.addClass("gif");
$("#resultsContainer").append("<p>" + rating + "</p");
$("#resultsContainer").append(image);
}
})
$(document.body).on("click", ".gif", function() {
var state = $(this).attr("data-state");
if (state === "still") {
$(this).attr("src", $(this).data("moving"));
$(this).attr("data-state", "moving");
} else {
$(this).attr("src", $(this).data("still"));
$(this).attr("data-state", "still");
}
})
})
}
displayButtons();
displayGIFs();
This all works on a standalone HTML document, but I can't seem to get the script to work properly. When the component loads and I inspect the page,
<script type="text/javascript" src="/scripts/giphyLogic.js"></script>
is there under the bundle.js script tag, but nothing from the script happens.
I get an "Uncaught SyntaxError: Unexpected token <" error that is attributed to giphyLogic.js:1 even though in the actual .js file, that line is blank. I've looked around, and this apparently happens when a file is included that doesn't exist, but the file is definitely there. I've double checked the path (by including an image in the same folder and loading the image successfully on the page) and it's correct.
Is there a way to resolve this, or am I going to have to create methods within the React component that I'm creating?
Do not mix jQuery and react. Learn how to use react properly by reading the well-written documentation. They can guide you through the many examples to get a simple app up and running.
Once again, do NOT use jQuery and react. jQuery wants to manually manipulate the DOM, and react manages a virtual DOM. The two will conflict more often than not, and you're going to have a bad time. If you have a very deep understanding of react, there are very few scenarios in which you could maybe use some jQuery, but nearly all of the time, it is to be avoided at all costs.
Obviously things like $.ajax() are fine, but for anything dealing with DOM manipulation, stay away. And if you only end up using jQuery for $.ajax() calls... you should switch to a leaner library like axios or use the native fetch API.

Categories

Resources