Run a Script in React JS/TSX file - javascript

I have a ReactJs file, Component.js and I want to execute a Script which looks like this:
<script type='text/javascript'>
window.onAmazonLoginReady = function() {
amazon.Login.setClientId('CLIENT-ID');
};
window.onAmazonPaymentsReady = function() {
//Will also add this button implementation method
showButton();
};
</script>
I want to include this Script in Component.js file, but couldn't think of any way. I had included this in index.js/index.html but I want the above script to be executed when the Component.js file loads.
This is my component.js file:
import React, { useContext, Component } from 'react';
import { Link } from 'react-router-dom';
const Component = () => {
return (
<div> Hello from Component </div>
);
};
export default Component;

You can just add the script inside the useEffect of the Component.js file like this :
useEffect(() => {
const setLoginClientId = () => {
amazon.Login.setClientId('CLIENT-ID');
};
// If this "onAmazonLoginReady" is a javascript event then you should add like this
// window.addEventListener("onAmazonLoginReady",setLoginClientId);
window.onAmazonLoginReady = setLoginClientId;
// Removed the unncessary function inside function,
// you can directly call showButton now
window.onAmazonPaymentsReady = showButton;
//Calling Set Client Id once, if you want
setLoginClientId();
},[]);
This will only run one time just after the Component loads.

Related

Nextjs: useEffect only once (if I use Link component)

I use Link component for open pages without reload:
<Link href="/home"><a>Home</a></Link>
<Link href="/page"><a>Page</a></Link>
This in my home:
const loadedRef = useRef(false)
useEffect(() => {
if(!loadedRef.current){
console.log("run")
loadedRef.current = true;
}
}, []);
This work fine for first load.
If I click on page and click on home, useEffect run again!
I want only and only once load useEffect even click another pages and return to home
useRef creates a value for this specific instance of the home component. If the instance unmounts, then that value goes away. If you want to make a global variable that persists even after the component has unmounted, do something like this:
import React, { useEffect } from 'react';
// Deliberately making this *outside* the component
let loaded = false;
const Home = () => {
useEffect(() => {
loaded = true;
}, []);
// ...
}
export default Home;
It occurs because the feature "shallow" of next.js
https://nextjs.org/docs/routing/shallow-routing
The official documentation asks to listen to the variable in the query string that receives the request. Generally, this variable is the name of your page like [slug].js. You can inspect the Network tab (F12) to see what is variable used in the query string also.
The below example inspects the slug variable.
import { useEffect } from 'react'
import { useRouter } from 'next/router'
// Current URL is '/'
function Page() {
const router = useRouter()
useEffect(() => {
// in my case the page is [slug].jsx
}, [router.query.slug])
}
export default Page

Duplicate componentDidMount logic with useEffect() to load external JavaScript on client side

I’m implementing a rich text editor into a NextJS project. There are no React components for it, and it runs only on the client side, so I have to load the JavaScript and CSS files from an external source and work around SSR. Please don't recommend to use another tool, as that is not an option.
The tool works fine as a class component, but I’d like to port it into a functional component. When I test the functional component, it works occasionally — namely, after I change my file and save (even if it's just adding a space). But as soon as I refresh the page, I lose the editor. I thought it was because the component hadn’t mounted, but now I check for that, yet the issue persists.
I’ve tried various approaches, including Next’s Dynamic import with SSR disabled, but so far only the class method below has worked (the editor works by binding to the <textarea> element):
import React from "react";
import Layout from "../components/Layout";
class Page extends React.Component {
state = { isServer: true };
componentDidMount() {
this.MyEditor = require("../public/static/cool-editor.js");
this.setState({ isServer: false }); // Trigger rerender.
var app = MyEditor("entry"); // Create instance of editr.
}
render(props) {
return (
<Layout>
<textarea id="entry"></textarea>
</Layout>
);
}
}
export default Page;
Last attempt at functional component:
import React, { useEffect } from "react";
import Layout from "../components/Layout";
function hasWindow() {
const [isWindow, setIsWindow] = React.useState(false);
React.useEffect(() => {
setIsWindow(true);
return () => setIsWindow(false);
}, []);
return isWindow;
}
const Editor = () => {
useEffect(() => {
const script = document.createElement("script");
script.src =
"http://localhost:3000/static/article-editor/cool-editor.js";
script.async = true;
document.body.appendChild(script);
return () => {
document.body.removeChild(script);
};
}, []);
var app = MyEditor("entry");
return (
<Layout>
<textarea id="entry"></textarea>
</Layout>
);
};
const Page = () => {
const isWindow = hasWindow();
if (isWindow) return <Editor />;
return null;
};
export default Page;
You can use useRef hook in <textarea> tag:
const refContainer = useRef(null);
return <textarea ref={refContainer}>
then useEffect to check if the the element has been mounted.
useEffect(() => {
if (refContainer.current) {
refContainer.current.innerHTML = "ref has been mounted";
console.log("hello");
}
}, []);
Check the code here: https://codesandbox.io/s/modest-dubinsky-7r3oz
Some of the things I could suggest changing:
var app = MyEditor("entry"); is being created on every render. Consider using useRef as a way to keep instance variable: https://reactjs.org/docs/hooks-faq.html#is-there-something-like-instance-variables
In Editor, the MyEditor variable is not defined.
hasWindow includes a useEffect that runs once (with empty dependency array), I don't think it needs the clean up function. To check staying at browser or server, you could simply use const isServer = type of window === 'undefined'
Custom hook should be named with prefix use

Can you run custom javascript tags inside a react component?

Apologies if this is very basic as I am a complete react beginner, I'm asking this question here as I have no idea where to start to get this working.
Im trying to convert this raw html code into a react app.
<body>
<div style="width: 600px; height: 400px;" id="aww-wrapper">
</div>
<script src="https://awwapp.com/static/widget/js/aww3.min.js">
</script>
<script type="text/javascript">
var aww = new AwwBoard('#aww-wrapper', {
});
</script>
</body>
This code creates a small whiteboard app on the webpage.
I have tried to implement it into the app component in react but am having trouble getting the 'var aww = ...' script to work.
import React from 'react';
import './App.css';
import ScriptTag from 'react-script-tag'
function App() {
return (
<div className="App">
<div style={{width:'600px', height:'400px'}} id="aww-wrapper">
</div>
<ScriptTag src="https://awwapp.com/static/widget/js/aww3.min.js" />
<ScriptTag type="text/javascript">
var aww = new AwwBoard('#aww-wrapper', {
});
</ScriptTag>
</div>
);
}
export default App;
I am using scripttag to get the external javascript onto the web page, but it isnt working for the 'var aww = ...' part.
It would be a huge help if anyone has a general direction that they can direct me to in order to implement the javascript into the react code.
You will need to create an initialing function wrapper for the AwwBoard. The function will create and configure a script object. The AwwBoard function will return a promise to the caller, which will provide the AwwBoard instance for later use (to access its methods) once the javascript has executed.
We also want to pass config params as well as a mount Ref for the component.
To achieve this, I created the following function which takes a ref (for the div you want to mount the AwwBoard) as well as configuration params. It loads the script, and resolves the promise with the instance.
const AwwBoard = (mountRef: React.Ref, params: Object = {}) => {
let promise = new Promise(function (resolve, reject) {
var script = document.createElement("script");
script.src = "https://awwapp.com/static/widget/js/aww3.min.js";
script.onload = function () {
//AwwBoard should be available on the window object after loading the script
const { AwwBoard } = window;
//create a new instance
var aww = new AwwBoard(`#${mountRef.id}`, params);
//resolve the promise and return the instance.
resolve(aww);
};
document.getElementsByTagName("head")[0].appendChild(script);
});
return promise;
};
export default AwwBoard;
Now we set up a div with a react ref, and a useEffect which loads the AwwBoard on "componentDidMount"
import React, { useEffect } from "react";
import "./styles.css";
import AwwBoard from "./AwwBoard";
export default function App() {
const awwBoardInstance = React.useRef(); //access methods on the board here
const awwBoardMountRef = React.useRef(null); //mounting ref for the AwwBoard
useEffect(() => {
AwwBoard(awwBoardMountRef.current, {}).then((instance) => {
awwBoardInstance.current = instance;
});
},[]);
return (
<div className="App">
<div
style={{ width: "600px", height: "400px" }}
id="aww-wrapper"
ref={awwBoardMountRef}
></div>
</div>
);
}
CodeSandbox
It would be better if you bundled the aww3.min.js into your app and then did something like this:
import React from 'react';
import { useEffect } from "react";
import './App.css';
import './aww3.min.js'
function App() {
useEffect(() => {
new AwwBoard('#aww-wrapper', {
});
}, [])
return (
<div className="App">
<div style={{width:'600px', height:'400px'}} id="aww-wrapper">
</div>
</div>
);
}
export default App;

how to execute a .js file containing multiple functions, via react jsx

i have a pre-existing .js file which contains multiple functions ( they call each other within the file) and event listeners.
How do i execute this .js file after elements have been rendered in the .jsx ?
I have tried adding export statement to the bottom of the .js file
export const A = functionOne();
export const B = functionTwo();
and adding import
import {A} from './index'
in the .jsx file
but it still gives react error that functions are not defined.
I know the file with the functions works perfectly because previously it was being used in a basic html / .js combination to render the page elements.By using at the bottom of the html
Use exports.funcName. I have called them in useEffect hook
CodeSandBox Link
App.js
import React, { useEffect } from "react";
import "./styles.css";
import { funA, funB } from "./functions";
export default function App() {
useEffect(() => {
funA();
funB();
}, []);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
</div>
);
}
Functions.js
exports.funA = () => {
console.log("This is from Function A");
};
exports.funB = () => {
console.log("This is from Function B");
};

how to send data from component to worker on button click?

could you please tell me how send data from component to worker on button click?
I tried like that not working
// xx.postMessage([first.value,second.value]);
could you please suggest where i am doing wrong .I want to do some background calculation and return result to component.
here is my code
import React, { useEffect } from "react";
import "./styles.css";
import worker from "./workerfile";
import WebWorker from "./setup";
export default function App() {
const buttonHan = () => {
alert("==g=");
// xx.postMessage([first.value,second.value]);
//console.log("Message posted to worker");
};
useEffect(() => {
let xx = new WebWorker(worker);
//xx.addEventListener("message", event => {
// });
}, []);
return (
<div className="App">
<h1>Hello CodeSandbox1</h1>
<button onClick={buttonHan}>BTN</button>
<h2>Start editing to see some magic happen!</h2>
</div>
);
}
code
https://codesandbox.io/s/bold-forest-s3guc?file=/src/App.js:212-263
This is the way i'd do it, idk if it's the supreme right way but i haven't had any problem declaring vars like this.
Also it's extremely useful when it comes to work with third party event handlers
export default function App() {
let xx = new WebWorker(worker); // Declare worker
// Constants declarations
const buttonHan = () => {
alert("==g=");
xx.postMessage("[first.value,second.value]");
console.log("Message posted to worker");
};
useEffect(() => {
xx.addEventListener("message", event => {
console.log(event)
});
}, [xx]); // useEffect executes when worker is setted
// this should be done even if variable is not a state
...

Categories

Resources