I want to load the Google APIs client library inside my index.html and the onLoad='someMethod' will invoke a method in a separate javascript file. That method will then print out to the console.
The client library is loaded without any problems but the message is not getting printed out the console and I think it's because the method is not getting invoked at all.
Here is my index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Welcome</title>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
</head>
<body>
<div id="app"></div>
<script src="lib/vendors.js"></script>
<script src="build/bundle.js"></script>
<script src="https://apis.google.com/js/client.js?onload=handleGoogleClientLoad"></script>
</body>
Here is the javascript file that contains the handleGoogleClientLoad method:
import React from 'react';
import ReactDOM from 'react-dom';
import {Button} from 'react-bootstrap';
class MyApp extends React.Component {
handleGoogleClientLoad() {
console.log('Success on load');
}
render() {
return (
<div>
<Button>Click Me</Button>
</div>
);
}
}
const app = document.getElementById('app');
ReactDOM.render(<MyApp />, app);
If this was plain javascript the method would look like this:
window.handleGoogleClientLoad = function() {
// Log to the console
};
Is there anything in es6 that is similar to the window object.
Component methods are not attached to the window object. MyApp.handleGoogleClientLoad is not going to be aliased to window.handleGoogleClientLoad which is what the google API script is likely trying to invoke.
If you want the Google API to call a method on your component you're going to have some trouble as there's no guarantee that your component will be mounted before or after your Google API script loads. If you want to guarantee that you'd have to inject the script after the component mounted and register the function in the componentDidMount method. You can use something like loadjs
componentDidMount() {
window.handleGoogleClientLoad = function() {
// log to console
}
loadjs('https://apis.google.com/js/client.js?onload=handleGoogleClientLoad')
}
the window object will still be available to you from your react component.. but the issue is that your defining your function just fine, but you're not calling it anywhere (is that jsonp syntax in the url of that script?). if you want that function to execute when you mount your component, you can make use of the component lifecycle hooks, specifically, componentDidMount
class MyApp extends React.Component {
handleGoogleClientLoad() {
console.log('Success on load');
}
componentDidMount(){
this.handleGoogleClientLoad();
}
render() {
return (
<div>
<Button>Click Me</Button>
</div>
);
}
}
if you want to keep the syntax you already have, then you can go ahead and access the window the way you suggest, but its thats definitely not a very react way of doing it
An old question but I found this while solving the problem myself. I am using React Helmet to put stuff in <head>. How I have done it is below. The key here is using defer when using <script> to load gapi. This means it does not run it until the document has been parsed, meaning our onload function window.gapiInit now exists.
From https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-defer:
This Boolean attribute is set to indicate to a browser that the script is meant to be executed after the document has been parsed, but before firing DOMContentLoaded.
import React from "react"
import { Helmet } from "react-helmet"
const HeadHelmet: React.FC = () => {
if (typeof window != "undefined") { // needed if SSR
window.gapiInit = () => {
console.log({ gapiInit: true })
// set state, what ever you need
}
}
return (
<Helmet>
<script
src="https://apis.google.com/js/api.js?onload=gapiInit"
defer={true}
></script>
</Helmet>
)
}
export default HeadHelmet
Related
I want to be able to customize the HTML based on the current locale. I have created a _document.js inside pages directory. And I used this code:
import { Html, Head, Main, NextScript } from 'next/document'
import { useRouter } from 'next/router'
export default function Document() {
const { locale } = useRouter();
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
But I get this error:
Error: Error: NextRouter was not mounted. https://nextjs.org/docs/messages/next-router-not-mounted
When I go to the URL specified, I see them saying that I'm using logic outside <Main />. Thus, how can I access locale inside _document.js?
I found NextRouter was not mounted Next.JS but even using next/navigation did not work for me, and I get this error:
Error: invariant expected app router to be mounted
useRouter() hook runs on the browser while _document.js runs on the server; that's the problem. For example, if you add a console.log('Hello Word') in Document before the return, it gets printed only in your development server, not on the browser.
You shouldn't be trying to use a logic related to hooks in _document.js, as it's not meant for, as the doc says:
React components outside of <Main /> will not be initialized by the browser. Do not add application logic here or custom CSS (like styled-jsx). If you need shared components in all your pages (like a menu or a toolbar), read Layouts instead.
It happened to me in the client component of app directory.
Instead of this
import { useRouter } from 'next/router'
import from
import { useRouter } from "next/navigation";
I am using React, and I am wondering how I can access the object that I have included as script in my html file within my own jsx file
This is an example that I got:
<script src="url-to-some-script"></script>
<div id="an-id-wrapper">
<div id="an-id"></div>
</div>
<script>
var settings = { config: "some-config", id: "an-id" };
TheObjectThatINeedToAccessFromScript.initialize(settings);
</script>
I want to do something like:
Add the script in my html file
Place the div in some React component
Be able to reach the TheObjectThatINeedToAccessFromScript so I can call initialize on it within my jsx file. Eg trough an import TheObjectThatINeedToAccessFromScript from "some-where";
How can I do an import on this script?
It is now available on the window object, so I can access it trough there:
window.TheObjectThatINeedToAccessFromScript.initialize(settings);
If I understand correctly, you just want to export your initialize() function from the script, and import it within your component. E.g:
function initialize() {
/*[...]*/
}
export { initialize };
import React, { useEffect } from 'react';
import { initialize } from './yourScriptFile';
/*[...]*/
function MyComponent() {
useEffect(() => {
initialize();
}, []);
return <div>{/*[...]*/}</div>
}
Unless it's absolutely vital, as a best practice, try to avoid binding things to the window. It can end in tears.
I want to use Mathjax on my website. I put in the <head> section of public/index.html:
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax#3/es5/tex-mml-chtml.js"></script>
And, in my component :
<template>
<div v-html="note_content"></div>
</template>
<script>
import { typeset, dummy_typeset } from '../assets/js/text_processing.js';
import showdown from 'showdown';
const converter = new showdown.Converter({ tables: true });
export default {
data () {
return {
}
},
computed: {
note_content: function() {
return typeset(this.exchange_data);
}
},
props: ['exchange_data'],
watch: {
note_content: function() {
Mathjax.typesetPromise();
}
}
}
</script>
However on runtime, I get the error :
Uncaught (in promise) ReferenceError: Mathjax is not defined
What I do not understand is that the css which is located in the head of public/index.html is correctly loaded and rendered in the component. Also I read elsewhere that loading external javascript this way should make it available to all components. What is wrong ?
I think it is connected to webpack config, but i might be wrong. Anyway, have you tried this method?
How to add external JS scripts to VueJS Components?
It enforces the script to be loaded.
Contrarily to what is written at https://docs.mathjax.org/en/latest/web/typeset.html, the syntax for asynchronous rendering is not :
Mathjax.typesetPromise()
But (notice the case):
MathJax.typesetPromise()
The typo could be detected from the surrounding context.
Also not that to use typeset Mathjax in a Vue component, the virtual DOM should be processed before calling the typesetPromise method, so an example of working code would be:
watch: {
note_content: function() {
this.$nextTick(MathJax.typesetPromise);
}
}
I am new to web development, This is just a simple code i created to test a new text editor I installed, I got this error while trying to import react because I was getting some other errors like; TypeError: Cannot read property 'createElement' of undefined
Please, how can i resolve this? is the import statement wrong?
import React, { Fragment } from 'react';
console.log("Testing");
var document;//made this declaration because I got a document undefined error
document.createElement("p"):
const p = document.createElement("p")
p.innerHTML = "This is to test the javascript";
const body = document.querySelector("body");
body.insertBefore(p,body.childNode[-1]);
<!DOCTYPE html>
<html>
<head>
<title>Testing vs code</title>
<link rel="stylesheet" type="text/css" href="styles.css"/>
</head>
<body>
<h1>Testing the vscode html preview package</h1>
<h2>Hello</h2>
<script type="module" src="js-prac.js"></script>
</body>
</html>
As per https://reactjs.org/docs/add-react-to-a-website.html, you need to add these two lines to your HTML file before importing your script:
<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>
I'm not sure that module loading is going to work the way you intend without using something like Create React App. You can remove the import statements and you can still reference React and ReactDOM in your script.
e.g.
'use strict';
const e = React.createElement;
class LikeButton extends React.Component {
constructor(props) {
super(props);
this.state = { liked: false };
}
render() {
if (this.state.liked) {
return 'You liked comment number ' + this.props.commentID;
}
return e(
'button',
{ onClick: () => this.setState({ liked: true }) },
'Like'
);
}
}
// Find all DOM containers, and render Like buttons into them.
document.querySelectorAll('.like_button_container')
.forEach(domContainer => {
// Read the comment ID from a data-* attribute.
const commentID = parseInt(domContainer.dataset.commentid, 10);
ReactDOM.render(
e(LikeButton, { commentID: commentID }),
domContainer
);
});
I Understand you want to create a simple application with React. I would recommend you to read this first https://kentcdodds.com/blog/how-to-react and then this one: https://reactjs.org/tutorial/tutorial.html
A react application can be created by importing script as you have started, but it is not the recommended way to build a react app.
Once you go through the above post, find a good tutorial of your choice on platforms of your choice be it blog or video based. I can name a few like udemy, frontend masters, pluralsight, and there are many more.
Take a look at ReactJS website.
You should create React app using Node package manager
npx create-react-app appName
or should link react scripts to your html
<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>
Also you can't redefine document object. This references your web page and you can access to element or DOM (Document Object Model) using document object.
I'm trying to get the current pathname in /page/_document.js file. I'm using a class, and my objective is to make a conditional with that value.
Here's my code (is basically the example in NextJS' page)
import Document, { Html, Head, Main, NextScript } from 'next/document'
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
You can get it by ctx.req.url or ctx.asPath but getInitialProps only executed at first time you access to app
Note: 's getInitialProps function is not called during client-side transitions, nor when a page is automatically statically optimized.
Note: Make sure to check if ctx.req / ctx.res are defined in
getInitialProps. These variables will be undefined when a page is
being statically exported for next export or automatic static
optimization.
Document