Adding React to an existing page and getting URL parameter inside .js - javascript

Based on official how to:
Add React to Website at https://reactjs.org/docs/add-react-to-a-website.html
I created test.html with content:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Add React in One Minute</title>
</head>
<body>
<h2>Add React in One Minute</h2>
<p>This page demonstrates using React with no build tooling.</p>
<p>React is loaded as a script tag.</p>
<!-- We will put our React component inside this div. -->
<div id="like_button_container"></div>
<!-- Load React. -->
<!-- Note: when deploying, replace "development.js" with "production.min.js". -->
<script src="https://unpkg.com/react#16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<!-- Load our React component. -->
<script src="test.js"></script>
</body>
</html>
And test.js:
'use strict';
const e = React.createElement;
class LikeButton extends React.Component {
constructor(props) {
super(props);
this.state = { liked: false };
}
componentDidMount() {
axios.get(`http://localhost:4000/api/v1/cars`)
.then(result => {
console.log(result.data[0].make);
})
}
render() {
if (this.state.liked) {
return 'You liked this.';
}
return e(
'button',
{ onClick: () => this.setState({ liked: true }) },
'Like'
);
}
}
const domContainer = document.querySelector('#like_button_container');
ReactDOM.render(e(LikeButton), domContainer);
The code above is working well.
I'm able to press Like button and see the change, also able to use libraries such as Axios.
Now I want to open http://localhost/test.html?param1=111&param2=222 and get these param1 and param2 variables inside test.js - React. Is that possible? How to achieve this?
Many thanks

Just as you perform a fetch in ComponentDidMount, you can check query params in the same lifecycle event. Building on the link shared by #Olian04, here's how that'd look:
componentDidMount() {
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.has("param1")) {
console.log(urlParams.get("param1"));
} else {
console.log("param1 was not found");
}
if (urlParams.has("param2")) {
console.log(urlParams.get("param2"));
} else {
console.log("param2 was not found");
}
}

Related

Adding React to HTML (without create-react-app installation)

I'm trying to follow this official React Documentation on how to add React to a website.
In file main.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Add React in One Minute</title>
</head>
<body>
<div id="root"></div>
<!-- Load React. -->
<!-- Note: when deploying, replace "development.js" with "production.min.js". -->
<script src="https://unpkg.com/react#18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#18/umd/react-dom.development.js" crossorigin></script>
<!-- Load our React component. -->
<script src = "states_clock.js"> </script>
</body>
</html>
In file states_clock.js
// states_clock.js
'use strict';
const domContainer = document.getElementById('root');
const root = ReactDOM.createRoot(domContainer);
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.props.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
function tick() {
root.render(<Clock date={new Date()} />);
}
setInterval(tick, 1000);
Both files are in the same folder.
When I open the html page in chrome, I get the error message:
Uncaught SyntaxError: Unexpected token '<' (at states_clock.js:11:7)
The < being complained about is that of the div in the js file.
This:
class Clock extends React.Component {
render() {
return (
<div>
is not JavaScript syntax - it's JSX syntax.
When you do
<script src = "states_clock.js"> </script>
as you would with any normal script tag, you're telling the browser to interpret and run it as a standard JavaScript file, which doesn't work, because it isn't. Add the attribute type="text/babel" to the script tag so it doesn't get run as JavaScript, and so that Babel Standalone sees that it's a script tag for it to process.
<script src="states_clock.js" type="text/babel"></script>
You could also write the JSX inline, like this:
<script crossorigin src="https://unpkg.com/react#18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#18/umd/react-dom.development.js"></script>
<div id='root'></div>
<script src="https://unpkg.com/#babel/standalone/babel.min.js"></script>
<script type="text/babel">
'use strict';
const domContainer = document.getElementById('root');
const root = ReactDOM.createRoot(domContainer);
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.props.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
function tick() {
root.render(<Clock date={new Date()} />);
}
setInterval(tick, 1000);
</script>
So, thanks to the comment by ChrisG, I understood that we're not supposed to use JSX in this part of the tutorial.
In that spirit, here's my solution:
'use strict';
const e = React.createElement;
const domContainer = document.getElementById('root');
const root = ReactDOM.createRoot(domContainer);
class Clock extends React.Component {
render() {
return e('div', null, e("h1", null, "Hello, world!"),
e("h2", null, "It is ", this.props.date.toLocaleTimeString(), "."));
};
}
function tick() {
root.render(e(Clock, {date: new Date()}, null))
}
setInterval(tick, 1000);
P.S.: Here's useful link that transforms JSX code into non-JSX code.

Having issues loading Scripts in my NextJS React application

I am trying to load some scripts in my NextJS application. I have followed the procedures outlined in the NextJS documentation but it doesn't seem to work in my application.
The link to the documentation is, https://nextjs.org/docs/basic-features/script.
I load the scripts in the _document.js file like this.
_document.js
import Document, { Html, Head, Main, NextScript } from "next/document";
import Script from "next/script";
class MyDocument extends Document {
static async getInitialProps(ctx) {
const originalRenderPage = ctx.renderPage;
// Run the React rendering logic synchronously
ctx.renderPage = () =>
originalRenderPage({
// Useful for wrapping the whole react tree
enhanceApp: (App) => App,
// Useful for wrapping in a per-page basis
enhanceComponent: (Component) => Component,
});
// Run the parent `getInitialProps`, it now includes the custom `renderPage`
const initialProps = await Document.getInitialProps(ctx);
return initialProps;
}
render() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
<Script
src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"
id={`jquery-1${+new Date()}`}
strategy="beforeInteractive"
></Script>
<Script
src="/webflow.js"
id={`webflow-1${+new Date()}`}
strategy="beforeInteractive"
></Script>
<Script
src="https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js"
id={`webfont-1${+new Date()}`}
strategy="beforeInteractive"
></Script>
<Script strategy="lazyOnload" id={`load-font-1${+new Date()}`}>
{`WebFont.load({
google: {
families: ["DM Sans:regular,500,700"]
}})`}
</Script>
</body>
</Html>
);
}
}
export default MyDocument;
I also tried this by putting the scripts in the Head tag but it was the same result.
_document.js
import Document, { Html, Head, Main, NextScript } from "next/document";
import Script from "next/script";
class MyDocument extends Document {
static async getInitialProps(ctx) {
const originalRenderPage = ctx.renderPage;
// Run the React rendering logic synchronously
ctx.renderPage = () =>
originalRenderPage({
// Useful for wrapping the whole react tree
enhanceApp: (App) => App,
// Useful for wrapping in a per-page basis
enhanceComponent: (Component) => Component,
});
// Run the parent `getInitialProps`, it now includes the custom `renderPage`
const initialProps = await Document.getInitialProps(ctx);
return initialProps;
}
render() {
return (
<Html>
<Head>
<Script
src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"
id={`jquery-1${+new Date()}`}
strategy="beforeInteractive"
></Script>
<Script
src="/webflow.js"
id={`webflow-1${+new Date()}`}
strategy="beforeInteractive"
></Script>
<Script
src="https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js"
id={`webfont-1${+new Date()}`}
strategy="beforeInteractive"
></Script>
<Script strategy="lazyOnload" id={`load-font-1${+new Date()}`}>
{`WebFont.load({
google: {
families: ["DM Sans:regular,500,700"]
}})`}
</Script>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
export default MyDocument;
I confirmed that the scripts were not working by checking the network tab and also as there functionalities that were meant to work on the website and dependent on the scripts were not working.

useState and useHooks in HTML

first of all, I can not use the "create-react-app" command in the current project.
so here I am trying to add my react code into a plain HTML file.
Here are my codes for HTML and js files.
can anyone tell me why my hooks and setState don't work properly?
Please guide me to solve it.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Add React in One Minute</title>
</head>
<body>
<p>React is loaded as a script tag.</p>
<!-- We will put our React component inside this div. -->
<div id="like_button_container"></div>
<!-- Load React. -->
<!-- Note: when deploying, replace "development.js" with "production.min.js". -->
<script src="https://unpkg.com/react#16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js" crossorigin></script>
<!-- Load our React component. -->
<script src="like_button.js"></script>
</body>
</html>
my like_button.js codes
'use strict';
const e = React.createElement;
const LikeButton = () => {
const [liked, setLiked] = useState(false);
useEffect(() => {
if (liked) {
return <div>You liked this</div>;
}
}, [liked]);
return e('button', { onClick: () => setLiked(true) }, 'Like');
};
const domContainer = document.querySelector('#like_button_container');
ReactDOM.render(e(LikeButton), domContainer);
Your trying to return from a useEffect, the return from a useEffect is for cleanUp of an effect,.
In fact you don't even require to use useEffect, you just need to change your render based on your liked state.
Also your example code you showed has JSX syntax, so not sure why your using createElement but I've created the example below without it, just in case..
eg.
const e = React.createElement;
const {useState, useEffect} = React;
const LikeButton = () => {
const [liked, setLiked] = useState(false);
return e('button', { onClick: () => setLiked(true) },
liked ? 'You Like this..' : 'Like');
};
const domContainer = document.querySelector('#like_button_container');
ReactDOM.render(e(LikeButton), domContainer);
<p>React is loaded as a script tag.</p>
<!-- We will put our React component inside this div. -->
<div id="like_button_container"></div>
<!-- Load React. -->
<!-- Note: when deploying, replace "development.js" with "production.min.js". -->
<script src="https://unpkg.com/react#16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js" crossorigin></script>

How to make function component from widget in next.js

So i want to use following html widget in my next.js app to verify user identities for my service. I have a problem with next.js not using the functions inside the script tag of html when i try to return it from function component. It doesn't even higlight it as a code.
So here is the html widget:
<!doctype html>
<html>
<head>
<!-- BLOCKPASS WIDGET SCRIPT -->
<script src="https://cdn.blockpass.org/widget/scripts/release/3.0.0/blockpass-kyc-connect.prod.js"></script>
</head>
<body>
<button id="blockpass-kyc-connect">Connect with Blockpass</button>
<script>
const blockpass = new BlockpassKYCConnect(
'my_client_id',
{
env: 'prod',
local_user_id: Date.now()
})
blockpass.startKYCConnect()
blockpass.on('KYCConnectSuccess', () => {
//add code that will trigger when data have been sent. ex:
//alert('Success!')
})
blockpass.on('KYCConnectClose', () => {
//add code that will trigger when the workflow is finished. ex:
//alert('Finished!')
})
blockpass.on('KYCConnectCancel', () => {
//add code that will trigger when the workflow is aborted. ex:
//alert('Cancelled!')
})
</script>
</body>
</html>
And i would like to make react component out of it. i was trying to implement it using the function component, to make it further reusable:
import React from 'react';
import Head from 'next/head';
export default function Blockpass () {
return (
<Head>
<!-- BLOCKPASS WIDGET SCRIPT -->
<script src="https://cdn.blockpass.org/widget/scripts/release/3.0.0/blockpass-kyc-connect.prod.js"></script>
</Head>
<body>
<button id="blockpass-kyc-connect">Connect with Blockpass</button>
<script>
const blockpass = new BlockpassKYCConnect(
'my_client_id',
{
env: 'prod',
local_user_id: Date.now()
})
blockpass.startKYCConnect()
blockpass.on('KYCConnectSuccess', () => {
//add code that will trigger when data have been sent. ex:
//alert('Success!')
})
blockpass.on('KYCConnectClose', () => {
//add code that will trigger when the workflow is finished. ex:
//alert('Finished!')
})
blockpass.on('KYCConnectCancel', () => {
//add code that will trigger when the workflow is aborted. ex:
//alert('Cancelled!')
})
</script>
</body>
)
}
unfortunately this doesn't seem to work for next.js, as the content of <script> tag is not recognized. How can i make this html scripts to work inside my next.js/react/jsx app.

Converting a dynamic HTML page to React/JSX

As a simple example, suppose I had these two files:
example.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8" />
<title>Button example</title>
<script type="text/javascript" src="ButtonHandler.js"></script>
</head>
<body id="body" onload="init()">
<button onclick=buttonHandler.writeToConsole()>Button</button>
<script>
function init() {
buttonHandler = new ButtonHandler();
}
</script>
</body>
</html>
ButtonHandler.js
function ButtonHandler() {
};
ButtonHandler.prototype.writeToConsole = function () {
console.log('Writing');
}
This simply prints to the console whenever the button is clicked.
Ignore that the ButtonHandler's constructor is empty, and that I could just easily call 'console.log' in the onclick directly. This is a simplified version of an issue I'm having, with several classes.
My question is, how would I go about translating this to React/JSX, ideally without modifying the Javascript files (in this case, just ButtonHandler.js). Ideally this means no exporting/importing, I'd like to do it how the HTML file does it - it just links to the script in the <\head>.
The closest I have is something like this:
convert.jsx
import * as React from 'react';
export default class Entry extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
buttonHandler = new ButtonHandler();
}
render() {
return (
<div>
<title>Button example</title>
<button onclick="buttonHandler.writeToConsole()">Button</button>
</div>
)
}
}
But I get the error that ButtonHandler is undefined. I followed this stackexchange answer and placed
<script type="text/javascript" src="[rest of path...]/ButtonHandler.js"></script>
in the public/index head, and I added the 'window.ButtonHandler' in componentDidMount(), but I still get the error that it's undefined.
Am I doing something wrong, and if not, what other approach can I take?
edit: When I put ButtonHandler.js in the public folder with index, and I console log the window, I see it appear as a function of window, like the stackexchange answer describes. This doesn't happen when I have it in another folder, though. Same error however.
edit 2: Seems the only solution is to put ButtonHandler.js in the public folder and then call it in the constructor like the selected answer says. Then add a
<button onClick={() => this.buttonHandler.writeToConsole()}>Button</button>
to call it.
In create react app, you should be able to add any js files to your public folder for use in your project. You just need to reference the files in your script like:
<script type="text/javascript" src="%PUBLIC_URL%/ButtonHandler.js"></script>
That will make sure that it looks in the public folder when building.
The only problem with that is that the files won't be minified in the bundle.
Edit
You will have to reference the global variable inside your component as well.
/* global ButtonHandler */
import * as React from 'react';
export default class Entry extends React.Component {
constructor(props) {
super(props);
this.buttonHandler = new ButtonHandler();
}
render() {
return (
<div>
<title>Button example</title>
<button onclick={this.buttonHandler.writeToConsole}>Button</button>
</div>
)
}
}
You'll want to import that ButtonHandler js code. If it's not something you've written yourself, the easiest thing to do would be to see if it already exists as a React package. If it's your own file, then you'll want to export the functions in ButtonHandler.js, import ButtonHandler in your React component, then you'll have access to them in the component.
ButtonHandler.js
export function writeToConsole() {
console.log('Writing');
}
convert.jsx
import React, { Component } from 'react';
import { writeToConsole } from './ButtonHandler';
export default class Entry extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<title>Button example</title>
<button onclick={this.writeToConsole}>Button</button>
</div>
)
}
}

Categories

Resources