Auto changing page title - reactjs

Does anybody know a way program or technique to change the title of any page based on the first founded tag? f.e.
For the most part, they resemble each other so it might be useful to implement it as default parameter, at least

For nextjs it's pretty simple to use Next-Seo,.This will render out the tags in the for SEO. At a bare minimum, you should add a title and description.
import { NextSeo } from 'next-seo';
const Page = () => (
<>
<NextSeo
title="Simple Usage Example"
description="A short description goes here."
/>
<p>Simple Usage</p>
</>
);
export default Page;

Use react-helmet. You can set the title same as the content of your first div.
import Helmet from "react-helmet";
export default function App() {
return (
<div className="App">
<Helmet>
<title>this is the title</title> // this can be a prop or a state data
</Helmet>
</div>
);
}
DEMO
PREVIEW

Related

NextJs 13 Experimental App Dir Hash in routes not directing to the hash id

I am using Nextjs 13 with the experimental App Dir but am not sure if this problem I am facing has anything to do with the issue I am facing. I have an id in my home page of "faqs" and when I click on the link, I can see it successfully goes to that link but does nothing in the browser. If I am on another page, I click the link and it takes me to the home page with the correct url but still stays on the top of the page and does not scroll to the indicated id. I did implement scroll={false} as suggested in the documentation but it makes no difference.
Here is a snippet of the relevant code parts:
"use client"
import React, { useState } from "react"
import { useRouter } from "next/navigation"
import Link from "next/link"
const Navigation = () => {
const router = useRouter()
...
In the return:
<Link scroll={false} href="/#faqs">FAQS</Link>
I Even tried:
<button type="button" onClick={() => router.push("/#faqs")}>FAQS</button>
In React the hash works fairly well but in next js, even only in client rendering it seems convoluted. If anyone knows what I am doing wrong or if there is a viable work around, I would sure appreciate it.
Thank you in advance.
If I am missing anything, please let me know.
I use hashtags a lot and I plan to start using the app directory in future projects, so I dug into this and it's not pretty. Apparently, NextJS uses a different package for app directory components client-side called "next/navigation". It's very different from "next/router". Also, when using "next/link" elements, NextJS does not trigger the onRouteChangeComplete event when location.hash changes but location.pathname does not.
So, in order to detect a hash change and scroll to the associated element, I finally had to implement this hack:
"use client"
import { Inter } from '#next/font/google'
import paragraph from './paragraph'
import Link from 'next/link'
import { useEffect, useState } from 'react'
const inter = Inter({ subsets: ['latin'] })
export default function Home() {
const [navClick, setNavClick] = useState(false);
useEffect(() => {
setTimeout(() => {
const hash = window.location.hash;
if (hash) document.querySelector(hash).scrollIntoView();
}, 0);
}, [navClick])
const toggleNavClick = () => setNavClick((oldVal) => !oldVal);
return (
<main>
<nav>
<ul>
<li>
<Link href="/#one" onClick={toggleNavClick}>Section One</Link>
</li>
<li>
<Link href="/#two" onClick={toggleNavClick}>Section Two</Link>
</li>
<li>
<Link href="/#three" onClick={toggleNavClick}>Section Three</Link>
</li>
</ul>
</nav>
<div className="container">
<section id="one">
<h1>Section One</h1>
<div dangerouslySetInnerHTML={{ __html: paragraph }} />
</section>
<section id="two">
<h1>Section Two</h1>
<div dangerouslySetInnerHTML={{ __html: paragraph }} />
</section>
<section id="three">
<h1>Section Three</h1>
<div dangerouslySetInnerHTML={{ __html: paragraph }} />
</section>
</div>
</main>
)
}
Since the hash change cannot be detected because no event is triggered, I basically created an event by toggling navClick each time a link is clicked. The navigation logic is enclosed in setTimeout() function because it triggers after window.location is updated.
Repo: https://github.com/designly1/next-hash-test
Demo: https://next-hash-test.vercel.app/

Pass page variables to layout in NextJS

I'm migrating my blog from Jekyll to NextJS and want to achieve the same functionality with the site layout.
The idea is to have metatags defined in a single layout file and fill values with variables that are defined on a page level.
I saw several solutions, one of them is to define metatags in _app.js as described here:
NextJS pass class from page to layout component
but from my understanding so far as a newbie in React/NextJS, it's better to utilize pageProps, but I can't figure out how to code it.
So far I have
_app.js
import 'bootstrap/dist/css/bootstrap.css'
import Layout from '../components/layout/layout';
export default function Blog({ Component, pageProps }) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
);
}
layout.js
import { Fragment } from 'react';
import Image from 'next/image';
import Head from 'next/head';
import MainNavigation from './main-navigation';
export default function Layout({ children }) {
return (
<Fragment>
<Head>
<meta name='viewport' content='width=device-width, initial-scale=1' />
<title>{children.title}</title>
</Head>
<MainNavigation />
<main>
{children}
</main>
</Fragment>
);
}
HomePage.js
export default function HomePage() {
return <div>HomePage</div>
}
I wanted to stick to the original code examples from the official documentation, so left layout as described in question, just
<Layout>
not
<Layout metas={pageProps.metas} ...>
So I just had to define props using getStaticProps:
export async function getStaticProps() {
return { props: { title: 'HomePage' } }
}
export default function HomePage() {
return <div>HomePage</div>
}
and then call it in layout as
{children.props.title}
not
{children.title}
The latter one would work if I just define a regular js variable in HomePAge.js as described in another SO thread I referenced. But I'm not sure if this approach somehow affects static website generation, so I decided to use NextJS built-in feature getStaticProps.
You can take the props you want in pageProps and pass them to the layout component:
<Layout metas={pageProps.metas} ...>
And use them in the <Layout />:
export default function Layout({ metas, children }) {
return (
<Fragment>
<Head>
<title>{metas.title}</title>
</Head>
...
</Fragment>
);
}

React 18: Hydration failed because the initial UI does not match what was rendered on the server

I'm trying to get SSR working in my app but I get the error:
Hydration failed because the initial UI does not match what was
rendered on the server.
Live demo code is here
Live demo of problem is here (open dev tools console to see the errors):
// App.js
import React from "react";
class App extends React.Component {
head() {
return (
<head>
<meta charSet="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<meta name="theme-color" content="#000000" />
<title>React App</title>
</head>
);
}
body() {
return (
<body>
<div className="App">
<h1>Client says Hello World</h1>
</div>
</body>
);
}
render() {
return (
<React.Fragment>
{this.head()}
{this.body()}
</React.Fragment>
)
}
}
export default App;
// index.js
import React from "react";
import * as ReactDOM from "react-dom/client";
import { StrictMode } from "react";
import App from "./App";
// const container = document.getElementById("root");
const container = document.getElementsByTagName("html")[0]
ReactDOM.hydrateRoot(
container,
<StrictMode>
<App />
</StrictMode>
);
The Html template shown in the live demo is served by the backend and generated using the following code:
const ReactDOMServer = require('react-dom/server');
const clientHtml = ReactDOMServer.renderToString(
<StrictMode>
<App />
</StrictMode>
)
// serve clientHtml to client
I need to dynamically generate <head></head> and <body></body> section as shown in the App class
I have been experiencing the same problem lately with NextJS and i am not sure if my observations are applicable to other libraries. I had been wrapping my components with an improper tag that is, NextJS is not comfortable having a p tag wrapping your divs, sections etc so it will yell "Hydration failed because the initial UI does not match what was rendered on the server". So I solved this problem by examining how my elements were wrapping each other. With material UI you would need to be cautious for example if you use a Typography component as a wrapper, the default value of the component prop is "p" so you will experience the error if you don't change the component value to something semantic. So in my own opinion based on my personal experience the problem is caused by improper arrangement of html elements and to solve the problem in the context of NextJS one will have to reevaluate how they are arranging their html element.
import Image from 'next/image'
/**
* This might give that error
*/
export const IncorrectComponent = ()=>{
return(
<p>
<div>This is not correct and should never be done because the p tag has been abused</div>
<Image src='/vercel.svg' alt='' width='30' height='30'/>
</p>
)
}
/**
* This will work
*/
export const CorrectComponent = ()=>{
return(
<div>
<div>This is correct and should work because a div is really good for this task.</div>
<Image src='/vercel.svg' alt='' width='30' height='30'/>
</div>
)
}
Importing and running some of the packages can cause this error too. For example, when I used Swiper.js package I encountered this problem. It's mostly because the package is using Window object somewhere.
Since it isn't a good practice to modify the content of the package itself, the best way to tackle such issues is to render the component only after the DOM is loaded. So you can try this.
const Index = () => {
const [domLoaded, setDomLoaded] = useState(false);
useEffect(() => {
setDomLoaded(true);
}, []);
return (
<>
{domLoaded && (
<Swiper>
<div>Test</div>
</Swiper>
)}
</>
);
};
export default Index;
This make the app client-side render, it's work for me:
export default function MyApp({ Component, pageProps }: AppProps) {
const [showChild, setShowChild] = useState(false);
useEffect(() => {
setShowChild(true);
}, []);
if (!showChild) {
return null;
}
if (typeof window === 'undefined') {
return <></>;
} else {
return (
<Provider store={store}>
<Component {...pageProps} />
</Provider>
);
}
}
I also using NextJS, Redux Toolkit
If you're using a table, you probably missed <tbody>
incorrect:
<table>
<tr>
<td>a</td>
<td>b</td>
</tr>
</table>
correct:
<table>
<tbody>
<tr>
<td>a</td>
<td>b</td>
</tr>
</tbody>
</table>
Removing the <p> tag solved my similar problem with NEXTJS..
The error is misleading as it's not about hydration but wrongly nested tags. I figured out the conflicting tags by removing html and reloading the page until I found the problem (binary search).
In my case it was caused by <a> within <Link>. I thought next.js requires the <a> within the Link but obviously that's not/no longer the case.
See next.js documentation about <Link> tag
I have react 18.2.0 with next 12.2.4 and I fix hydration with this code
import { useEffect, useState } from 'react'
import { Breakpoint, BreakpointProvider } from 'react-socks';
import '../styles/globals.scss'
function MyApp({ Component, pageProps }) {
const [showChild, setShowChild] = useState(false)
useEffect(() => {
setShowChild(true)
}, [])
if (!showChild) {
return null
}
return (
<BreakpointProvider>
<Component {...pageProps} />
</BreakpointProvider>
)
}
export default MyApp
this issue comes in nextjs because dangerouslySetInnerHTML support only div tag. if you insert with other tag its not work.
<div dangerouslySetInnerHTML={{__html:data.description}}></div>
So let me explain why this error can occur in your NEXT JS application.
There are some tags that you can't use inside another tag.
For example you can't use div inside an anchor td tag. You can't use p tag inside a span. Same goes for other tags like table, ul etc.
You need to go to your code and remove all the invalid tags used.
In my case, I used a a tag inside span which in invalid.
This is invalid
<span>
<a target="_blank" href="https://askhumans.io"> Login </a>
</span>
This is valid.
<a target="_blank" href="https://askhumans.io"> <span> Login </span> </a>
it will work:
function MyApp({ Component, pageProps }) {
const [showing, setShowing] = useState(false);
useEffect(() => {
setShowing(true);
}, []);
if (!showing) {
return null;
}
if (typeof window === 'undefined') {
return <></>;
} else {
return (
<RecoilRoot>
<MainLayout>
<Component {...pageProps} />
</MainLayout>
</RecoilRoot>
);
}
}
export default MyApp;
here I used recoil for state managing.
If you're using NextJS and Material UI with emotion as the styling engine, then you may need to check the semantics of your components. You can find hints in the errors logged to the browser console.
Example: adding Box component inside Iconbutton will cause an error
There's no need to create a custom NextJS _document.js file because #emotion/react version 10 and above works with NextJS by default.
If u use html tags u want to place them in correct way and correct order. in NEXTJS.
ex: If u use table.
-> U must add the tbody tag
<!-- Wrong -->
<table>
<tr>
<td>Element</td>
<td>Element</td>
</tr>
</table>
<!-- Correct Way -->
<table>
<tbody> <!-- This is a Must -->
<tr>
<td>Element</td>
<td>Element</td>
</tr>
</tbody>
</table>
in Next v13 and upper you shouldn't use <a> as child inside <Link>.
if you use that, you'll get error.
in this case I use that in another way:
const Child = () => <a>hello my friend</a>
const Parent = () => {
return (
<Link href="/">
<Child />
</Link>
)
}
here I got this error, and I changed child structure for remove <a> to resolve it.
So mine is a NEXT JS app.
I am using the react-use-cart module and it seems it has issues with react #18.0.0.
I am not sure how this is possible but downgrading to react #17.0.2 removed my errors.
Previously I was using react #18.0.0
I simply ran npm uninstall react react-dom and installed versions #17.0.2.
Wahala, everything now works as expected.
I had the same issue when tried to put a div inside Card Text of React-Bootstrap.
The error can be reproduced by:
import type { NextPage } from 'next'
import { Card } from 'react-bootstrap';
...
const testPage : NextPage = () => {
...
return (
...
<Card.Text>
<div>It's an error</div>
</Card.Text>
...
)}
export default testPage
To fix it, i just removed the html tag.
I think that some react components doesn't accept html tags inside.
Make sure to wrap in Suspense the lazy modules you import.
In my case I imported
const Footer = React.lazy(() => import('../Footer/Index'));
but I was using it just like a normal module
<Footer />
I wrapped it in Suspense and the error was gone.
<Suspense fallback={<div>Loading...</div>}>
<Footer />
</Suspense>
Bottom line
If this error is given to you on the home page, try to comment some of the components you use until you find where the error is coming from.
In my case, it's an user error in nested list. I forgot adding a ul in li so it was just nested lis.
Make sure you dont have next/Link nested, I needed to refactor the code and forgod that I had a next/Link before wrapping the image.
for example
<CompanyCardStyle className={className}>
//Open Link
<Link href={route('companyDetail', { slug: company.slug })}>
<a className='d-flex align-items-center'>
<div className='company-card'>
<div className='d-flex align-items-center col-name-logo'>
<div className='company-logo'>
//Remove link and let the <a> child
<Link href={route('companyDetail', { slug: company.slug })}>
<a><img src={company.logoUrl} width={'100%'} /></a>
</Link>
</div>
<h6 className='mb-0'>{company.name}</h6>
</div>
.....
</div>
</a>
</Link>
</CompanyCardStyle>
I had this issue when I moved the pages directory in NextJs. I solved it by deleting the .next folder and rebuilding it using yarn build.
I solved this problem by NextJs dynamic import with ssr: false
import dynamic from 'next/dynamic'
import { Suspense } from 'react'
const DynamicHeader = dynamic(() => import('../components/header'), {
ssr: false,
})
export default function Home() {
return (
<DynamicHeader />
)
}
just go to browser, chrome->three bars button on top right corner->more tools->clear browsing history-> delete cookies.
no more error
i ran this piece of code and the problem went away
import "#/styles/globals.css";
import { useEffect, useState } from "react";
export default function App({ Component, pageProps }) {
const [showChild, setShowChild] = useState(false);
useEffect(() => {
setShowChild(true);
}, []);
if (!showChild) {
return null;
}
if (typeof window === "undefined") {
return <></>;
} else {
return <Component {...pageProps} />;
}
}
I had the same issue with Next.js and Faker.js, and i just use conditional rendering and it's solved. I think it happened because the values from faker.js changes twice when page first loading. Code below may help you.
`
export default function Story() {
const [avatar, setAvatar] = useState(null);
const [name, setName] = useState(null);
useEffect(() => {
setAvatar(faker.image.avatar());
setName(faker.name.findName());
}, []);
return (
<>
{avatar && name && (
<div>
<Image
src={avatar}
alt="Story Profile Picture"
width={50}
height={50}
/>
<p>{name}</p>
</div>
)}
</>
);
}
`
You Can wrap your component that cause this error with Nossr from mui(material-ui)
import NoSsr from "#mui/material/NoSsr";
<NoSsr> {your contents} </NoSsr>
to get more info: https://mui.com/material-ui/react-no-ssr/
In my case, when I used reverse() function before mapping my list, I was getting a similar error.
In my case, neither making the HTML more semantic nor modifying the _app.tsx to check if the window was loaded.
The only solution, for now, was to downgrade the React version and the React DOM.
I'm using NextJS.
I switched to version 17.0.2.
Hydration failed because the initial UI does not match what was rendered on the server
You should check the console for errors like:
Warning: Expected server HTML to contain a matching <div> in <div>.
and fix them.
Copied from https://github.com/vercel/next.js/discussions/35773
In my case, I faced this problem because I had used <img /> tag instead of Next.js <Image /> tag because I couldn't use tailwind classes with the <Image /> tag. Replacing the <img /> tag with Next.js <Image /> tag solved the issue for me. Then I wrapped the <Image /> tag with a div tag and added the classes to that.
I ran into same issue using NextJS with Material UI.
Actual solution is to use NextJS dynamic import.
In the example below do not import header component as:
import Header from "../components/header"
Instead do:
import dynamic from 'next/dynamic'
const DynamicHeader = dynamic(() => import('../components/header'), {
suspense: true,
})
Check the NextJS documentation below:
https://nextjs.org/docs/advanced-features/dynamic-import
I had this issue even with create-next-app without any changes and tried with different browser and different profiles. I see that there is no problem with them so I investigate my extensions but it didn't solve the problem. Finally I've solved it with investigating chrome dev tools settings. My problem related with "Enable Local Overrides". So I've unchecked that and it solved.
Enable Local Overrides on Chrome Settings

React tailwind, cannot pass tailwind css from parent to child

I am running into a simple issue that doesn't seem to have an answer on quick google search or Tailwind doc.
I am a Vuejs user but I have started learning React. I have opted to use TailwindCSS for testing my React application but I noticed there is some differences of Tailwind usage between Vuejs and React.
In Vue, I can control a child component via the parent component like so:
Parent component:
<template>
<div class="w-screen">
<ChildComponent class="w-1/2 mx-auto" />
</div>
</template>
With the child being able to centre on screen through the above parent component as should in the ChildComponent's class.
However, when I tried to do the same in React like so:
Parent component:
import Homepage from './views/Homepage';
function App() {
return (
<div className='bg-black w-screen'>
<Homepage className="w-1/2 mx-auto"/>
</div>
);
}
export default App;
Nothin happens when I placed the CSS at the Homepage child component from the parent.
I am sure there is a simple answer but I wasn't about to search the doc or use any keywords to find this problem. Anyone got a hint or confirm this is intended in React or have I done something wrong with the installation?
This is less of a Tailwind question and more of a React question. You cannot use className on the Homepage component without passing it as a prop. In your case, Homepage is not expecting any className. So while making your Homepage component you have to provide a prop called 'className' then it will work fine.
Or if you simply use a div in place of Homepage it will work normally. Have a look at this codesandbox link
You need to consider that <Homepage/> is a React component and cannot accept HTMLAttrs just like that.
this example might clear it:
const app = () => {
<div className="bg-black">
<Homepage className="bg-red" />
</div>
}
const homePage = (props) => {
<div className={props.className}>
<h1 className="bg-red">hi</h1>
</div>
}
the className that you pass to <Homepage/> is actually a props rather than Html attribure.
In Vue it's fairly straightforward but in react you need to be explicit and use className in your component
// Creating component
const Button = ({ className, children }) => {
return <button className={`${className} bg-red-500`}>{children}</button>
}
export default Button
// Using component
<Button className="text-white">MyButton</Button>
import Homepage from './views/Homepage';
function App() {
return (
<div className='bg-black w-screen'>
<Homepage className="w-1/2 mx-auto"/>
</div>
);
}
export default App;
views/Homepage
you have to receive props that are going to be passed as className
const homePage = ({className}) => {
<div className={className}>
<h1 className="bg-red">hi</h1>
</div>
}
export default homePage
then export your component

Have a common header layout in nextjs

I have 2 pages user.js and nonuser.js and one component header. user.js and nonuser.js have same functionality with slight changes in UI. Now I want to integrate all this. Like when I visit the page by default table of user.js must be viewed. One click of nonuser.js it should change to the nonuser.js table. And I want header to be same for both, content in textbox should not change when I switch between pages.
I'm new to next.js and react
header.js
import React, { Component } from 'react';
import '../Header/header.css';
import { Menu, Input, Icon } from 'antd';
import Link from 'next/link';
class HeaderComponent extends Component {
render() {
return (
<div className="navbar">
<div className="header">
<div className="col-1">
<div className="menu">
<div>
<Link href="/User"><a>Users</a></Link>
</div>
<div>
<Link href="/nonUser"><a>Non Users</a></Link>
</div>
<Input className="text-box" placeholder="Enter name" prefix={<Icon type="search" ></Icon>}></Input>
</div>
</div>
</div>
</div>
)
}
}
export default HeaderComponent
user.js
class User extends Component {
render() {
return (
<React.Fragment>
<div className="ant-table-row">
<div className="table-head-text">
<span className="text">Users({data.length})</span>
<Pagination defaultCurrent={1} total={100} />
</div>
<Table
rowKey={data._id}
columns={this.columns1}
rowSelection={this.rowSelection}
onExpand={this.onExpand}
dataSource={data} />
</div>
</React.Fragment>
)
}
I didn't add nonuser component, its same as user component
index.js
import Header from '../components/Header/header';
import Layout from '../components/Layout';
function App() {
return (
<Header/>
<div>
</div>
)
}
export default App;
I've done this, On first landing the only header is there and on clicking user link in header, header disappears and only table of user is shown.
EDIT:
I tried this header appears in both and I placed a textbox in header .textbox value clears when I switch between pages.
user.js and nonuser.js
render(){
return(
<Layout>
<div>.....</div>
</Layout>
)
}
Also tried
index.js
render() {
return (
<Layout>
<div>
</div>
</Layout>
)
}
layout.js
const Layout = ({children}) => (
<div>
<Header></Header>
{children}
</div>
);
From what I make of your question, you want to use HeaderComponent as a common header for both pages? Then I'd suggest placing it in your components/Layout file. Next will wrap all pages in the layout component, thus adding your header to all pages.
I'm also wondering why you have an index.js file? Unless it's placed in pages/ folder, it isn't something you normally do in Next. The pages user.js and nonuser.js should also be placed in the pages/ folder. Next will then automatically load the to files and provide them under the routes /user and /nonuser (based on the name of the file). This will also make Next wrap each page in the layout component mentioned above.
I'd suggest looking into NextJS learning guide. It provides a very good introduction to NextJS and will make it a lot easier to use NextJS if you. They have a lesson explaining how to use Shared Components which explains exactly what you seem to be looking for.
Hope this helps a bit.
Edit:
Example using _app.js
The following is an example of how to use a custom layout component in next using _app.js. It's based on Nexts own example.
// components/Layout.js
import React, { Component } from 'react';
import Header from './Header';
class Layout extends Component {
render () {
const { children } = this.props
return (
<div className='layout'>
<Header />
{children}
</div>
);
}
}
// pages/_app.js
import React from 'react';
import App from 'next/app';
import Layout from '../components/Layout';
export default class MyApp extends App {
render () {
const { Component, pageProps } = this.props
return (
<Layout>
<Component {...pageProps} />
</Layout>
)
}
}
To get more information on how to make use of _app.js properly, check out their documentation on custom app.

Resources