useState and useHooks in HTML - javascript

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>

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.

How to include externally loaded script to all bundles created by React.lazy?

I wanted divide my project into two bundles. Here's my simplified App.js
import React, { Suspense, useState, useEffect, useRef } from 'react';
import loadGif from './images/731.gif';
const HospitalDashboard = React.lazy(() => import('./HospitalDashboard'));
const OperatorDashboard = React.lazy(() => import('./OperatorDashboard'));
function App () {
const [credentials, setCredentials] = useState(null);
return (
<Suspense fallback={<img className='load' src={loadGif}/>}>
{credentials.role == 'operator' ?
<OperatorDashboard/> :
<HospitalDashboard/>}
</Suspense>
);
}
export default App;
and here's my simplified index.html
<!DOCTYPE html>
<html lang="en">
<head>
<script type="text/javascript" src="https://cdn.jsdelivr.net/jquery/latest/jquery.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/momentjs/latest/moment.min.js?version=256"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.css" />
<title>Dashboard</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
Both in OperatorDashboard and HospitalDashboard I am using daterangepicker followingly:
import $ from 'jquery';
...
useEffect(()=>{
$('#datePicker').daterangepicker(initOptions,onCallback)
},[])
In HospitalDashboard everything works fine but in OperatorDashboard I am getting this error:
jquery__WEBPACK_IMPORTED_MODULE_1___default(...)(...).daterangepicker is not a function
It is somehow related to React.lazy and bundles but I don't know how to solve it. If I use ordinary import without React.lazy, everything works fine again. Thanks for help!

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

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");
}
}

How to perform import/export in client-side React JSX using Babel-Standalone

I'm using Babel-Standalone to use JSX in a React application without using NPM. Babel apparently translates 'import' statements into 'require' statements; importing 'require.js' and other dependencies to make this work produces more errors.
Surely, there must be a simple way to perform an import/export in the context of client-side JSX. Please advise (no Node/NPM/Webpack solutions are sought here; CDN of appropriate library(ies) and rewrite of import statement, etc., are sought).
<!doctype html>
<html lang="en-us">
<head>
<title>React JSX Babel-Standalone Import/Export Problem</title>
<meta charset="utf-8">
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<script type="text/babel">
// See MyExport.js text below this SCRIPT
// Goal: to employ <MyExport /> in the return of App.
// import MyExport from "./MyExport";
const App = () => {
return (
<div>Hello</div>
);
};
ReactDOM.render(<App />, document.querySelector("#root"));
</script>
<!-- MyExport.js:
const MyExport = () => {
return (
<div>MyExport</div>
);
};
export default MyExport;
-->
</body>
</html>
There is a solution: (1) The JSX script containing the export must be included in a SCRIPT element along with the others; it cannot simply be referenced by another script without. (2) Both that JSX script and the JSX script importing from it must have the custom attribute data-plugins="transform-es2015-modules-umd" along with the expected attribute type="text/babel". Run the following HTML, a modification of what was provided in the question, which provides the solution (you'll have to create MyExport.js locally to run it):
<!doctype html>
<html lang="en-us">
<head>
<title>React JSX Babel-Standalone Import/Export Problem</title>
<meta charset="utf-8">
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<script data-plugins="transform-es2015-modules-umd" type="text/babel" src="./MyExport.js"></script>
<script data-plugins="transform-es2015-modules-umd" type="text/babel">
import MyExport from "./MyExport";
const App = () => {
return (
<MyExport/>
);
};
ReactDOM.render(<App />, document.querySelector("#root"));
</script>
<!-- MyExport.js:
const MyExport = () => {
return (
<div>MyExport element is imported!</div>
);
};
export default MyExport;
-->
</body>
</html>
I hope this helps someone else.
you should include first all needed component files, then run the app js file
Example:
<div id="root-react"></div>
<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/babel-standalone#6/babel.min.js" crossorigin></script>
And the file's tree is something like:
js/app.js
js/subcomponent.js
The app.js content is for example:
"use strict";
class MainReact extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<strong>app.js</strong> is loaded<br/>
<SubComponent />
</div>
)
}
}
ReactDOM.render(<MainReact />, document.getElementById("root-react"));
subcomponent.js content:
"use strict";
class SubComponent extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<span> SubComponent-is-working </span>
)
}
}
customElements.define('subcomponent', SubComponent);
The file inclusion in the html file should be:
<script type="text/babel" src="js/subcomponent.js"></script>
<script type="text/babel" src="js/app.js"></script>
Hope it helps somebody.
CodePen demo
Babel isn't a module bundler or a module system implementation, babel is just a transpiler to provide access to the latest JS features that aren't supported in the browser or node.
If you want to use ES Modules without any third parties like webpack, rollup, etc. have a look at https://developers.google.com/web/fundamentals/primers/modules.
You should be able to do something like:
<script type="module">
import MyExport from "./url/to/MyExport.mjs";
const App = () => {
return (
<div>Hello</div>
);
};
ReactDOM.render(<App />, document.querySelector("#root"));
</script>
JS Modules via script tags is only supported in the latest versions of major browsers: https://caniuse.com/#feat=es6-module
Also, you'll need to workaround the fact that babel-standalone needs your script tags to be text/babel EDIT: the workaround is using a data-type="module" tag as well as the type="text/babel" tag: https://babeljs.io/docs/en/babel-standalone#usage

Categories

Resources