Issue with NextJS navigation - next.js

I am getting the following error when I navigate to Gallery and Contact Link, except when I click on home link ('/').
head-manager.js:2
Uncaught (in promise) TypeError: Cannot read property 'join' of undefined
at head-manager.js:2
Below is my header.js component:
import Link from 'next/link'
import { COLORS, FONT_SIZE } from '../theme/constants'
const Header = () => {
return (
<header>
<Link href='/'>
<a className='site-name'>Name</a>
</Link>
<nav>
<Link href='/'>
<a>Home</a>
</Link>
<Link href='/gallery'>
<a>Gallery</a>
</Link>
<Link href='/contact'>
<a>Contact</a>
</Link>
</nav>
</header>
)
}
export default Header

I don't think the issue is in the above component, but possibly in your _document.js, _app.js, or relevant page that is trying to update title, or other Head properties. You will see this error if the property you are using to set the value does not exist:
if props.myUndefinedProperty does not exist below, you will see the:
head-manager.js:2 Uncaught (in promise) TypeError: Cannot read property 'join' of undefined
import Head from 'next/head';
...
return (
...
<Head>
<title>{props.myUndefinedProperty}</title>
</Head>

I found the issue. I am using getStaticProps to fetch data from sitedata.json in index.js file and passing contents of file as props through Layout component. Thats how my header and Head components receive site title and description info. But I am not passing them through the Gallery and About page files. I figured if I get them once from index file it would be able to use them globally, but that is not the case. I have to fetch that data using getStaticProps on every page file, which got rid of error.

Related

Integrating ShareThis with Next.js

Has anyone tried to integrate ShareThis with Next.js?
I'm getting "Hydration failed because the initial UI does not match what was rendered on the server." and this, I have ascertained, is down to the inclusion of the ShareThis script tag.
I'm not sure what I need to do in order to resolve this error.
This is my _document.tsx file, containing the offending script tag:
import { Html, Head, Main, NextScript } from "next/document";
const Document = () => (
<Html>
<Head>
<script
type="text/javascript"
src={`https://platform-api.sharethis.com/js/sharethis.js#property=${process.env.NEXT_PUBLIC_SHARETHIS_PROPERTY_ID}&product=sop`}
async
defer
></script>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
export default Document;
Of course, the NEXT_PUBLIC_SHARETHIS_PROPERTY_ID variable from my .env file is being correctly populated.
You should be using next/script to load 3rd party scripts like ShareThis. Here's their documentation https://nextjs.org/docs/basic-features/script
Make sure to apply the <Script src="" /> component OUTSIDE of the next/head component, either above of below it.
Hope this helps.

Is there a way to use Materialize CDN with Next.js?

I am building a Next.js application and would like to use Materialize CDN with it. In React, I would just add the CDN links in the public/index.html file and would be good to go. Next doesn't seem to have that and I am stuck on how to do this.
I have tried with
npm install materialize-css#next --save
And I import it into the pages/_app.tsx like so:
import 'materialize-css/dist/css/materialize.min.css';
import 'materialize-css'
When it is just the first import alone, it works well, but when I import the second one to add JS, it throws me this error:
Server Error
ReferenceError: window is not defined
This error happened while generating the page. Any console logs will be displayed in the terminal window.
Also, with this kind of import, I can't make any customization to the CSS which is why I would like to use the CDN. I have been at it for days with no luck.
Using Materialize via CDN
As Daniel mentioned in his answer, you can add the CDN links in your custom _document, so both CSS and JavaScript get properly loaded in the browser.
// /pages/_document.js
class MyDocument extends Document {
render() {
return (
<Html lang="en">
<Head>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css"
/>
</Head>
<body>
<Main />
<NextScript />
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
</body>
</Html>
);
}
}
Because Materialize uses Web APIs internally, you'll need to access the Materialize instance attached to the window inside a useEffect. This prevents the ReferenceError: window is not defined error when the page gets pre-rendered on the server by Next.js.
Here's a small example of how to use Materialize in a component that renders a carousel.
const MaterializeCarousel = () => {
useEffect(() => {
const elems = document.querySelectorAll('.carousel');
const instances = window.M.Carousel.init(elems);
}, []);
return (
<div className="carousel">
<a className="carousel-item" href="#one!"><img src="https://lorempixel.com/250/250/nature/1" /></a>
<a className="carousel-item" href="#two!"><img src="https://lorempixel.com/250/250/nature/2" /></a>
<a className="carousel-item" href="#three!"><img src="https://lorempixel.com/250/250/nature/3" /></a>
<a className="carousel-item" href="#four!"><img src="https://lorempixel.com/250/250/nature/4" /></a>
<a className="carousel-item" href="#five!"><img src="https://lorempixel.com/250/250/nature/5" /></a>
</div>
);
};
Using Materialize via npm package
Another option is to use to library through its npm package materialize-css.
You first need to import the global CSS, as you did, in _app.
import 'materialize-css/dist/css/materialize.min.css';
The JavaScript code can't be loaded here, as mentioned earlier it utilizes Web APIs that don't work on the server.
Instead, taking the same carousel component as an example, you should dynamically import materialize-css inside a useEffect so it's only loaded on the client-side.
const MaterializeCarousel = () => {
useEffect(() => {
const init = async () => {
const M = await import('materialize-css');
const elems = document.querySelectorAll('.carousel');
const instances = M.Carousel.init(elems);
};
init();
}, []);
return (
<div className="carousel">
<a className="carousel-item" href="#one!"><img src="https://lorempixel.com/250/250/nature/1" /></a>
<a className="carousel-item" href="#two!"><img src="https://lorempixel.com/250/250/nature/2" /></a>
<a className="carousel-item" href="#three!"><img src="https://lorempixel.com/250/250/nature/3" /></a>
<a className="carousel-item" href="#four!"><img src="https://lorempixel.com/250/250/nature/4" /></a>
<a className="carousel-item" href="#five!"><img src="https://lorempixel.com/250/250/nature/5" /></a>
</div>
);
};
Instead of doing it in the _app.tsx do it in a _document.js file. This file is where you augment the html and body tags in NextJS projects. It's important to note that it has to be a .js file, not .tsx.
This file is not present in your project by default and it is auto-generated by nextJS, but you can create it in the pages folder to override the default one and import the CDN there.
You have the _document.js template and more information in the official documentation.

next.js _document.js didn't get called

I have a small problem with next.js _document.js. I want to support Arabic, so, I add lang="ar" to Html component. But, in the page rendered there is no lang attribute in HTML. Hope somebody help me.
In order for Next.js to show updates made in _document you must stop and restart Next.js.
You must restart Next.js after making changes in _document, *.env, or any Next.js config files.
pages/_document.{ jsx | tsx }
import NextDocument, { Head, Html, Main, NextScript } from 'next/document';
class Document extends NextDocument {
render = () => (
<Html lang="ar" dir="rtl">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
export default Document;

Next 11 and adding Script tags not working. No scripts are rendered

I added my google tag manager to _app.js file, and its not showing. None of the scripts I am loading via the new "Script" tag are working.
<Head>
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no" />
<Script
src={`https://cdn.somelink.coom/${process.env.COOKIE_KEY}/block.js`}
strategy="beforeInteractive"
/>
<Script
src="https://cdn.somelink.com/scripttemplates/stub.js"
strategy="beforeInteractive"
/>
<Script
src={`https://www.googletagmanager.com/gtag/js?id=${process.env.GOOGLE_KEY}`}
strategy="afterInteractive"
/>
These are not working. Nothing is downloaded in the network tab etc. Nothing shows up on the page. Any thoughts?
Reminder: this is in the _app.js file.
Note: My pages are static generated.
next/script should not be wrapped in next/head
Ref.: Script Component
Do something like this:
import Script from "next/script";
const App = ({ Component, pageProps }) => (
<>
<Script
id="scriptAfterInteractive"
src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"
/>
{/* eslint-disable-next-line react/jsx-props-no-​spreading */}
<Component {...pageProps} />
</>
);
export default App;
In addition to the requirement that Script (next/script) not be wrapped in Head (next/head), it should also not be placed within a custom _document.tsx unless you are not passing strategy="beforeInteractive" as mentioned in the docs.
I was unable to load a Cloudflare analytics script when placing it in _document.tsx, but it loaded successfully as a sibling to Component in _app.tsx.

Meteor+React Error: Uncaught Invariant Violation: _registerComponent(...): Target container is not a DOM element

I am looking at LevelUpTuts Meteor+React for everybody series.
I am having " Uncaught Invariant Violation: _registerComponent(...): Target container is not a DOM element. " error but I don't know where the problem is.
client/Main.html
<head>
<title>myResolutions</title>
<meta charset="utf-8"/>
</head>
<body>
<div id="target-render"></div>
<script src="./App.js"></script
</body>
In my App.jsx
client/App.jsx
import React from 'react';
import ReactDOM from 'react-dom';
class App extends React.Component{
render() {
return (
<h1> Hello World </h1>
)
}
}
if(Meteor.isClient){
Meteor.startup(function(){
ReactDOM.render(<App />,document.getElementById("render-target"));
});
}
It looks like in the html you have the id as "target-render", and in the javascript you have the id as "render-target". They need to match.
I guess the problem is coming from this line:
It shouldn't be here.
and I highly recommend you to use official Meteor tutorials instead of anything else:
https://www.meteor.com/tutorials/react/creating-an-app
First of, you need to import Meteor, import { Meteor } from 'meteor/meteor'; and then you don't need to include <script src="./App.js"></script> in your html. Note you have a typo on that line, you didn't properly close the script tag

Resources