I try to convert a HTML template (Bootstrap 5) to Gatsby template. CSS and pages working expected but in HTML template there is a main.js file and it need to load after page rendered.
I modify the main.js file like that;
import { Swiper } from "swiper/swiper-react.cjs.js";
import GLightbox from "glightbox/dist/js/glightbox.min.js";
import AOS from "aos";
AOS.init();
export const onClientEntry = () => {
window.onload = () => {
console.log("deneme");
/*rest of code*/
};
};
In here I try two way. One of them, I create main.js file inside src->components->assets->js folder. Then in layout.js I try to import that file.
import React from "react";
import PropTypes from "prop-types";
import { Breadcrumb } from "gatsby-plugin-breadcrumb";
import Header from "./partials/header";
import { Helmet } from "react-helmet";
import useSiteMetadata from "./hooks/siteMetadata";
import "./assets/css/style.css";
import "./assets/js/main.js"
However in here in debug not hit the any method inside onClientEntry. So I decide to change my way.
Secondly, I try to add code inside main.js to gatsby-browser.js. That's time again getting Cannot read property 'addEventListener' of null because of html is not ready yet.
My file structure:
window (and other global objects like document) are not available during the SSR (Server-Side Rendering) because this action is performed by the Node server (where for obvious reasons there's no window, yet) so you can't access directly to onload function. In addition, accessing these global objects outside the scope of React (without hooks) can potentially break React's hydration process.
That said, you have a few approaches:
Using React hooks. Specifically, useEffect with empty dependencies ([]) fits your specifications, since the effect will be fired once the DOM tree is loaded (that's what empty deps means):
const Layout = ({children}) => {
useEffect(()=>{
mainJs();
}, [])
return <main>{children}</main>
}
Assuming that your ./assets/js/main.js file has a mainJs() function exported, this approach will load it when the DOM tree is loaded. For example:
const mainJs= ()=> console.log("deneme");
The console.log() will be triggered when the HTML tree is built by the browser. Tweak it to adapt it to your needs.
Adding a window-availability condition like:
export const onClientEntry = () => {
if(typeof window !== 'undefined'){
window.onload = () => {
console.log("deneme");
/*rest of code*/
};
}
};
Alternatively, you can output the console.log directly in your onClientEntry, depending on your needs:
export const onClientEntry = () => {
console.log("deneme");
/*rest of code*/
};
You can even combine both approaches by adding a useEffect in your gatsby-browser if it works for you.
Related
I'd like to import this javascript package in React
<script src="https://cdn.dwolla.com/1/dwolla.js"></script>
However, there is no NPM package, so I can't import it as such:
import dwolla from 'dwolla'
or
import dwolla from 'https://cdn.dwolla.com/1/dwolla.js'
so whenver I try
dwolla.configure(...)
I get an error saying that dwolla is undefined. How do I solve this?
Thanks
Go to the index.html file and import the script
<script src="https://cdn.dwolla.com/1/dwolla.js"></script>
Then, in the file where dwolla is being imported, set it to a variable
const dwolla = window.dwolla;
This question is getting older, but I found a nice way to approach this using the react-helmet library which I feel is more idiomatic to the way React works. I used it today to solve a problem similar to your Dwolla question:
import React from "react";
import Helmet from "react-helmet";
export class ExampleComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
myExternalLib: null
};
this.handleScriptInject = this.handleScriptInject.bind(this);
}
handleScriptInject({ scriptTags }) {
if (scriptTags) {
const scriptTag = scriptTags[0];
scriptTag.onload = () => {
// I don't really like referencing window.
console.log(`myExternalLib loaded!`, window.myExternalLib);
this.setState({
myExternalLib: window.myExternalLib
});
};
}
}
render() {
return (<div>
{/* Load the myExternalLib.js library. */}
<Helmet
script={[{ src: "https://someexternaldomain.com/myExternalLib.js" }]}
// Helmet doesn't support `onload` in script objects so we have to hack in our own
onChangeClientState={(newState, addedTags) => this.handleScriptInject(addedTags)}
/>
<div>
{this.state.myExternalLib !== null
? "We can display any UI/whatever depending on myExternalLib without worrying about null references and race conditions."
: "myExternalLib is loading..."}
</div>
</div>);
}
}
The use of this.state means that React will automatically be watching the value of myExternalLib and update the DOM appropriately.
Credit: https://github.com/nfl/react-helmet/issues/146#issuecomment-271552211
for typescript developers
const newWindowObject = window as any; // cast it with any type
let pushNotification = newWindowObject.OneSignal; // now OneSignal object will be accessible in typescript without error
You can't require or import modules from a URL.
ES6: import module from URL
What you can do is make an HTTP request to get the script content & execute it, as in the answer for how to require from URL in Node.js
But this would be a bad solution since your code compilation would depend on an external HTTP call.
A good solution would be to download the file into your codebase and import it from there.
You could commit the file to git if the file doesn't change much & are allowed to do it. Otherwise, a build step could download the file.
var _loaded = {};
function addScript(url) {
if (!loaded[url]) {
var s = document.createElement('script');
s.src = url;
document.head.appendChild(s);
_loaded[url] = true;
}
}
how to load javascript file from cdn server in a component
Add the script tag in your index.html and if you are using Webpack, you can use this webpack plugin https://webpack.js.org/plugins/provide-plugin/
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 am trying to lazy load constant file in react. This constant file is not react component just simple javascript files like below :
// constant.js
export const customFunction = () => {
}
// component.js
const {
customFunction,
} = React.lazy(() => import('./constant.js'));
This I am not able to find in browser under developer tools source option. Also due to this getting customFunction undefined error. This code work if do normal import. customFunction using under useEffect()
import {
customFunction
} from './constant.js';
Do not wrap import statement inside React.lazy. Instead only use import() which returns a Promise and it gets resolved to the contents of the mentioned file
Here is a working example
I am new to the Next.JS framework and do not fully understand the logic of importing data from a component page. For example, I have created a page like example.js in my components folder, where I am running an API that pulls data to a graph. Then, inside my index.js file, where I want my graph to be displayed, it is giving me a 'Unhandled Runtime Error', because the API function is not being triggered inside of example.js.
This is how I am importing the page in /pages/index.js:
import dynamic from 'next/dynamic'
const Example = dynamic(() => import('../pages/example.js'))
//Later on inside of my return
<Example />
And from my example.js page I am exporting as follows:
function Example(props) {
return <div>
... my code
}
Then below that, I have the following inside my example.js:
export default Example
Followed by my getStaticProps function:
export async function getStaticProps() {
const res = await fetch("")
const data = await res.json()
if (!data) {
return {
notFound: true
}
}
return {
props: {
data: data.reverse(),
},
}
}
If I use this exact code on my index.js it functions properly. Any ideas as to why this doesn't run, and any solutions as to a fix?
Edit for clarity: My getStaticProps function is in my example.js file, and my issue is that it is not being triggered.
Next.js does a lot of magic to handle server-side rendering, static-site generation and code splitting, and it does it all from within the /pages folder. It's important to know that components within the /pages folder work a little differently from a regular React component. Here are some tips for you that should solve your problem.
1. Put your page components inside the /pages folder.
Components inside this folder can have a default export (the component), along with named exports (the additional Next.js-specific functions like getStaticProps). If Next.js finds the exported functions, it will run them.
2. Use next/dynamic only for dynamic imports.
Dynamic imports are lazy-loaded -- this will affect Next.js' automatic code-splitting and potentially server-side rendering. I don't know the exact inner workings, but my guess is dynamically-loading a Page component (which are special in Next) is probably what's breaking things. I tend to only use dynamic imports when I have a 3rd-party component that breaks SSR, so I need to dynamically import it so it's not server-side rendered.
The simplest way to handle this is probably:
in /pages/index.js:
import Example from '../path/to/example';
export default (props) => (
<div>
<p>My page component</p>
<Example />
</div>
);
export async function getStaticProps() {
return {
props: {
data: // ...
}
};
}
With this solution above, you can use dynamic imports as well -- what matters is that you have your Next.js-specific function exported from the file in /pages immediately:
in /pages/index.js:
import dynamic from 'next/dynamic';
const Example = dynamic(() => import('../components/example'));
export default (props) => (
<div>
<p>My page component</p>
<Example />
</div>
);
export async function getStaticProps() {
return {
props: {
data: // ...
}
};
}
Update to solve "My getStaticProps function is in my example.js file, and my issue is that it is not being triggered.":
Next.js will only call a getStaticProps function that is exported from a file in the /pages directory. If you want to define your getStaticProps method from another directory, you can do that, but you need to import it into /pages and then re-export it like so:
in /components/example.js:
export default () => (
// ... component ...
);
export function getStaticProps() {
// ... function ...
};
and in /pages/index.js:
import Example, { getStaticProps } from '../components/example';
export default Example;
export {
getStaticProps
}
This should work. However, you can't import Example using dynamic imports in this case.
Need to import "validation.js" file within another javascript file in reactjs once the main file render method is completes it execution
import './Validations';
should render this JS file once the main component's render method complete its execution
What you're trying to achieve is not really the way react likes to behave and probably is a mistake. if you need some extra functionality to be available in your component you could define a class, put your external logic in there and then instantiate an object from that class in your component's constructor or render method, and use whatever functionality you need in from there.
You can use react-loadable library to lazy load javascript file.
import Loadable from 'react-loadable';
const LoadableTest = Loadable({
loader: () => import('./validations.js'),
loading() { // you could write your spinner while the file is being loaded.
return <div>Loading...</div>
}
});
class MyComponent extends React.Component {
render() {
return <LoadableTest/>;
}
}