NextJs app directory - page gets remounted when slug changes - next.js

I was trying to migrate my nextjs application to app directory, but I found a weird behaviour.
When I have a route in the pages folder like this:
// `pages/test/[slug]/index.tsx`
export default function Page() {
useEffect(() => {
console.log('mount')
return () => {
console.log('unmount')
}
}, [])
return <>
<Link href="/test/1">1</Link>
<Link href="/test/2">2</Link>
</>
}
if I change the page by clicking one of the links, the slug changes, but component doesn't remount. However, when I move this file to app/test/[slug]/page.tsx and mark the file with 'use client';, clicking the link unmounts page component and then mounts it again.
Is this expected behaviour? If so how can I achieve behaviour from pages directory in app?

Related

nextjs links without strings

Im new to nextjs, and Im checking if it will be good for the app that will have pretty complex and messy internal navigation. Just checked their documentation and I see that they recommend usage
of Link component like this <Link href="/your_path">Path</Link>. A bit scary is that I have to provide 'your_path' as a string so every time i change page file name I have to manually update code that redirects to this page. Is there any solution that allows me to define routing on my own so I can write something like (pseudocode)
routes = [
...
{
page : 'page_name',
path : 'path_to_page'
}
...
]
So instead of using string I can do <Link href="{route.path}">Path</Link> or Im condemned to use this file-system based router with all consequences?
The simple answer is yes!
When you want to change a user route in NextJs you have 2 options,
The first is with the <Link> Element that you can specify a href to where it directs.
And you also have a useRouter hook for more complex routing for example if the user does an action that requires moving him into a different route you can do it internally in your handlers.
For more information about useRouter hook.
What I usually do is storing my routes in an object
const ROUTES = {
HOME: "/",
ABOUT: "/about"
}
and wherever you call routes you just use the object so F.E
With Link tag
<Link href={ROUTES.ABOUT}>ABOUT PAGE</Link>`
with useRouter hook
// Inside a React Component
const router = useRouter();
const handleNavigateToAbout = () => {
router.push(ROUTES.ABOUT);
}
return (
// SOME JSX
<button onClick={handleNavigateToAbout}> Go to about page! </button>
)

nextjs reload page with Link component

I have a simple nextjs 13 application (appDir) with 2 pages and a <Link/> component navigation.
first page Home - static
second page Test - receiving dynamic random content on the server side (fetch) from a third-party source.
Problem: When the application is rendered everything works fine, but when I try to switch between pages, my test page shows the old content, I can refresh the browser to get the actual data, is very similar to navigating through regular links <a/>, but i need without reloading the entire application.
Q: How can I force nextjs 13 to reload the Test page when I switch between pages with <Link/> component?
// src/components/navbar.tsx
'use client'
import {usePathname} from "next/navigation";
import Link from "next/link";
const navItems = [
{text: 'Home', href: '/'},
{text: 'Test', href: '/test'}
];
const Navbar = () => {
const pathname = usePathname();
return <nav className="nav nav-masthead justify-content-center float-md-end">
{navItems.map((item: { text: string, href: string, link?: boolean }, idx: number) => (
<Link key={idx} href={item.href} className={`nav-link${item.href === pathname ? ' active' : ''}`}>
{item.text}
</Link>
)
)}
</nav>
}
export default Navbar;
// src/app/test/page.tsx
import * as crypto from "crypto";
const getData = async () => {
const res = await fetch('http://localhost:3000/random-data', {cache: 'no-store'});
if (!res.ok) {
throw new Error('Failed to fetch data');
}
return res.json();
}
export default async function Page() {
return <p>{crypto.createHash('sha256').update(JSON.stringify(await getData())).digest('hex')}</p>
};
I've recently asked about this same topic on their feedback discussion on github: https://github.com/vercel/next.js/discussions/41745?sort=new#discussioncomment-4620262
The cause of the problem is Link is only doing client side navigation and seems to serve a cached state of the previously visited component. You'll notice that the client never calls back to the server and thus the server component never runs the second time.
I've been searching for days, but haven't found a way to force Link to reload or force refresh the component to re-render.
My conclusion is that if you have dynamic data that needs to refreshed periodically, it's best to render it in a client component and not use a server component for now.
Also, if you'd like to use Suspense, you'll need to use a library like SWR or React Query for any client side data fetching.

TinaCMS/Nextjs github pages 404 when accessing root url in

I just deployed a TinaCMS page on github pages using github actions. It seems to work fine except on initial access to the root URL. On this initial load, Nextjs renders a 404 error page with a link 'Return to home'. When clicking this link, the browser's URL is still the root URL and the home page is rendered correctly.
when I access a sub page like example.com/posts directly, the page is rendered correctly.
when I do a build and export locally and open the files using a local nginx server, the home page is rendered correctly on initial access.
in my next.config.js a have the following:
async rewrites() {
return [
{
source: "/",
destination: "/home",
} ...
so what could the problem be in conjunction with github pages?
the complete source code is here: https://github.com/mtnstar/web
the page is accessible on https://mtnstar.net
I found a temporary fix, although the 404 page is flashing up for a second and then the right home age is rendered.
so I added a useEffect hook to initially redirecting to the browser current url.
import React from "react";
import "../styles.css";
import { useRouter } from 'next/router'
const App = ({ Component, pageProps }) => {
const router = useRouter();
React.useEffect(()=>{
router.push(window.location.href)
},[])
return <Component {...pageProps} />;
};
so another way to permanently fixing this would be appreciated

Next.js SSG page component gets new object from props every time it renders

I'm using Next.js and i want to build simple SSG page, which take immutable data from db on build time and render it to some list of elements. For that purpose i'm using getStaticProps. Here's source code of this page:
import Layout from '../components/Layout'
import utilStyles from '../global-styles/utils.module.css'
import { getSortedPostsData } from '../utils/posts'
import { useMemo } from 'react'
const Home = ({ allPostsData }) => {
const posts = useMemo(() => {
console.log('useMemo log');
return allPostsData.map(({ id, date, title }) => (
<li className={utilStyles.listItem} key={id}>
{title}
<br />
{id}
<br />
{date}
</li>
))
}, [allPostsData])
return (
<Layout home>
<ul className={utilStyles.list}>
{posts}
</ul>
</Layout>
)
}
export const getStaticProps = async () => {
console.log('getStaticProps run')
const allPostsData = await getSortedPostsData()
return {
props: {
allPostsData
}
}
}
export default Home
In production build I can see 'getStaticProps run' log once in console. All required data gets from database and passes to Home component in props. This component renders posts list fine. When i switch to this page in my browser first time I can see exactly one 'useMemo log' in the console. But...
Every time I switch to another page and then back to Home page I see another 'useMemo log' in the browser console too. I'm not understand why this is happening. This page loaded exactly once (not on every page switch). Data for this page is obtained exactly once (in build time). But Next.js passes new array (array with new address) in Home page props every time it renders. Why this is happening and how can i avoid this behavior to memoize my posts list and not render it every time I switch the page?

NextJS route gives 404 when not using Link

I have a Next.js page, where the pages are statically generated (using next export). It's a dynamic route, but I will only fetch data on the client after the initial page load (in a useEffect).
The path is something like: /pages/foo/[id].tsx. This is in fact the only route which is going to exist.
My problem is:
If I access the URL directly (e.g. typing in https://mysite.fake/foo/1337 into the URL bar) I get a 404.
If I navigate to that route using a <Link /> it does work as expected
If I then reload the page, I get a 404 again.
On local dev, it works fine. The problem only exists when deployed.
The page in question is using the router.query, but I have the same problem with a completely static page (e.g. just /pages/bar/baz.tsx).
Example:
export const Home: NextPage = () => {
const router = useRouter()
const { id } = router.query
const headerText = id ? `Hello ${id.toString()}` : ''
// in a later iteration, I will use the query id to fetch data in a useEffect
return <h1>{headerText}</h1>
}
As far as I understand from the Next.js documentation on dynamic routing and data fetching this should be possible to do.
My next.config.js is very bare:
/** #type {import('next').NextConfig} */
module.exports = {
reactStrictMode: true,
}
What am I doing wrong?

Resources