Next.js Discord

Discord Forum

Execute on every page

Answered
Silver posted this in #help-forum
Open in Discord
SilverOP
So i am trying to have a verifySession() function run on every page/navigation.

Layout.jsx
import DashboardWrapper from '@/app/components/DashboardWrapper'
import { verifySession } from '@/app/components/session'

export default async function RootLayout({ children }) {
  await verifySession()
  return (
    <DashboardWrapper>{children}</DashboardWrapper>
  )
}


to see when the function is executed i have a console.log
export async function verifySession() {
 console.log('executed')
}


However when using the Link from 'next/link' the pages are cached (or whatever its called) so the function is only executed the first time.

what would be the possible solution?
Answered by Silver
here is the solution i will utilize since the point is to ensure user is auth before accessing data. using NextJS with MUI for loading animation @Ray

template.jsx
'use client'

import { useEffect, useState } from 'react'
import { verifySession } from '@/app/components/session'

export default function DashbaordTemplate({ children }) {
   let [isAuth, setIsAuth] = useState(false)

   useEffect(() => {
      (async function () {
         console.log('Template.jsx executed')
         let auth = await verifySession()
         setIsAuth(auth)
         if (!auth) {
            location = '/logout'
         }
      })()
   }, [])

   if (!isAuth) {
      return null
   }

   return <>{children}</>
}
View full answer

165 Replies

You can use a middleware to check the session @Silver
@B33fb0n3 You can use a middleware to check the session <@679398056679964693>
SilverOP
cant since it is checking the database and prisma does not support it natively
Ah verifySession comes from prisma?
Black Caiman
Did you try adding export const dynamic = 'force-dynamic';?
@B33fb0n3 Ah verifySession comes from prisma?
SilverOP
no? it is a function that uses prisma
@Black Caiman Did you try adding export const dynamic = 'force-dynamic';?
SilverOP
yes. makes no difference
However when using the Link from 'next/link' the pages are cached (or whatever its called) so the function is only executed the first time.
this sounds like client page caching ngl... you can stop this with using a instead of Link... but it only lasts 30sec iirc
i mean you can invalidate it with router.refresh iirc
i don't know many ways of deleting the cache/not using it
@riský i mean you can invalidate it with router.refresh iirc
SilverOP
can you explain router.refresh?
https://nextjs.org/docs/app/api-reference/functions/use-router (and scoll a little untill you see refresh in list)
but if you load page and wait a min and then click link, does it achieve what you want?
SilverOP
never mind so it does work. however
router.refresh()
just keeps executing until the application crashes
try putting it in a single useEffect with no deps (just empty list like nomal)
but i can actually see why it would infinite load
and my solution isn't even that good as you have 2 requs...
best thing is to actually disable prefetcing on the link
SilverOP
i got a good solution!
let [currentPathname, setCurrentPathname] = useState(pathname)
let pathname = usePathname()
let router = useRouter()

useEffect(() => {
  if (currentPathname !== pathname) {
   setCurrentPathname(pathname)
   router.refresh()
  }
 }, [currentPathname, pathname])
only renders once
niceee
can you try disableing prefetching on the links also tho
i think its a way better method....
@riský can you try disableing prefetching on the links also tho
SilverOP
<Link prefetch={false}/> didnt work for me previously
oh
i think i missunderstood you then
ahh actually i remember what you wanted now
yeah i think the refresh might be best 😭
SilverOP
yes and it seems to work perfectly and does not seem to affect performance as it still has the prefetch and memory cache
@riský oh
SilverOP
thank you for the assistance!
also can i ask why you actually need to do the verify every page?
as is first time not good enough?
@riský also can i ask why you actually need to do the verify every page?
SilverOP
authentication. verifying session is still valid. since a user session can be revoked or invalidated
hmm i see, and you don't want stale data too
@riský hmm i see, and you don't want stale data too
SilverOP
exactly! stale data can be a security issue too if not handle correctly.
i haven't tried it, but maybe experimental.optimisticClientCache in next config could bypass the cache... https://github.com/vercel/next.js/blob/canary/packages/next/src/client/link.tsx#L141
only try if you have time tho
hmm this may not actully work ater looking further at it, so disregard it
isnt the RootLayout only render once? so you need to do router.refresh to make it render again?
lol you have a really good point
how did i miss that 😭
so its not related to cache lol
i mean he just wants no cache ig
which is why just use a link...
ah ok
@Ray ah ok
its bad calling it cache here (and i hope you get what i mean), and you have a really good point (thanks for telling me)
i think maybe template is better then?
@riský i think maybe template is better then?
yea worth a try
@Ray isnt the RootLayout only render once? so you need to do router.refresh to make it render again?
SilverOP
same issue even if it is located in the individual pages. being in the RootLayout is not the issue
@Ray because router cache
SilverOP
yup. so router.refresh() with my other code is the soluton
however, that would hurt the performance i guess
middleware is best place for that, I think you can create a route handler to check the session with prisma and you can fetch the api in middleware
and fetch the api in middleware
SilverOP
oh i get what you mean
i will test it out in a bit and see
export async function middleware(req: NextRequest) {
  await fetch(new URL("/api/session", req.nextUrl));
}
@Ray ts export async function middleware(req: NextRequest) { await fetch(new URL("/api/session", req.nextUrl)); }
SilverOP
middleware doesnt appear to execute every time either
oh wait
it was caching. hold on
nope nevermind. the middleware itself seems to get cached. cant see a workaround to that @Ray
based on https://github.com/vercel/next.js/discussions/43675 people are using route.refresh() to solve the middleware cache anyways...
// template.tsx
"use client";

import { useEffect } from "react";
import { verify } from "./action";

export default function Template({ children }: { children: React.ReactNode }) {
  useEffect(() => {
    verify();
  }, []);
  return <div>{children}</div>;
}

this works
@Ray yea there is still a 30 sec router cache with <Link prefetch={false} />
SilverOP
its odd because it doesnt always cache the middleware...
im using server action
it works, i just tried
@Ray it works, i just tried
SilverOP
ReactServerComponentsError:

You're importing a component that needs next/headers. That only works in a Server Component but one of its parents is marked with "use client", so it's a Client Component.
Learn more: https://nextjs.org/docs/getting-started/react-essentials


you cannot access cookies in client component
no im using server action
its a server action
client component can execute server action
@Ray client component can execute server action
SilverOP
ah forget about 'use server'
no
no cache at all
it is a template.tsx
SilverOP
oh give me a sec
@Ray it is a `template.tsx`
SilverOP
got it to work. only issue now is that it is executing twice
because react strict mode
it will run once in production mode
@Ray it will run once in production mode
SilverOP
about to check build
now when bulding i get the following error
[Error]: Dynamic server usage: Page couldn't be rendered statically because it used `cookies`. See more info here: https://nextjs.org/docs/messages/dynamic-server-error

note my verify function is async since it is checking the database
search for cookies and see what page you are importing it
this is not related to the template i think, you can rename it to _template.tsx and try building again
@Ray this is not related to the template i think, you can rename it to _template.tsx and try building again
SilverOP
you are right. just some weird code that decided to break. unrelated
yea because of server action
SilverOP
so realistically doesnt it have the same amount of effect on the performance as router.refresh()?
@Silver so realistically doesnt it have the same amount of effect on the performance as `router.refresh()`?
router refresh will full reload your page from layout to other component. While server action just will make a extra http request on page load.

you should try with yourself which suit your usecase better
i don't know how your application load the data
no
the page will still render while still posting the server action.
try add a timeout on the server action, the page will still render and not awaiting it
"use server";

import { redirect } from "next/navigation";

export async function verify() {
  await new Promise((resolve) => setTimeout(resolve, 5000));
  console.log("verfiy");
  redirect("/");
}

like this
SilverOP
here is the solution i will utilize since the point is to ensure user is auth before accessing data. using NextJS with MUI for loading animation @Ray

template.jsx
'use client'

import { useEffect, useState } from 'react'
import { verifySession } from '@/app/components/session'

export default function DashbaordTemplate({ children }) {
   let [isAuth, setIsAuth] = useState(false)

   useEffect(() => {
      (async function () {
         console.log('Template.jsx executed')
         let auth = await verifySession()
         setIsAuth(auth)
         if (!auth) {
            location = '/logout'
         }
      })()
   }, [])

   if (!isAuth) {
      return null
   }

   return <>{children}</>
}
Answer
SilverOP
@Ray ever seen the template.jsx not be executed? from what i am seeing if i am visiting the same parent path it is not execute template.jsx multiple times. e.g. domain.com/website, domain.com/website/view, domain.com/website/edit will only execute template.jsx once. but if i switch between domain.com/website and domain.com/dashboard it executes every time
@Ray try create a `template.tsx` in app/website/template.tsx?
SilverOP
but then it will double execute the code no? since app/website/template.jsx will be nested in app/template.jsx
SilverOP
@Ray any suggestions?
@Silver but then it will double execute the code no? since app/website/template.jsx will be nested in app/template.jsx
templates create a new instance for each of their children on navigation.
@Ray try create a `template.tsx` in app/website/template.tsx?
so this should do what you need
or create a client component and wrap the page you need to run instead of using template
SilverOP
what i mean is wont localhost:3000/website/view execute /app/website/template.jsx and /app/template.jsx meaning template.jsx will run twice? @Ray
btw, if you need something to run on every page navigation (like auth) this should happen in middleware which you can keep to matching paths
https://nextjs.org/docs/app/building-your-application/routing/middleware
@Silver what i mean is wont localhost:3000/website/view execute /app/website/template.jsx and /app/template.jsx meaning template.jsx will run twice? <@743561772069421169>
does it run twice? Im not sure about it. if it run twice, maybe create a client component and wrap the page you need instead of using template
@Ray does it run twice? Im not sure about it. if it run twice, maybe create a client component and wrap the page you need instead of using template
SilverOP
That just goes back to the main issue... since a component is not executed on every navigation
just like the code inside template
@Ray just like the code inside template
SilverOP
already tested on my end. using a component only executes once.
the useEffect only execute once ?
@Ray the useEffect only execute once ?
SilverOP
yes because of cache i suppose
i dont think so
it is just a client side fetching
@Ray it is just a client side fetching
SilverOP
please test it and you will see it does not execute every time
already tested and it execute every time
@Ray already tested and it execute every time
SilverOP
can you provide your code then...
same code in template
@Ray same code in template
SilverOP
i used that exact code and it did not run every time...
@Ray same code in template
SilverOP
please show me how you created the component 🙂
"use client";

import { verify } from "@/app/action";
import { useEffect, useState, useTransition } from "react";

export default function Every({ children }: { children: React.ReactNode }) {
  const [show, setShow] = useState(false);

  useEffect(() => {
    (async function () {
      await verify();
      setShow(true);
    })();
  }, []);

  if (!show) {
    return <div>loading...</div>;
  }

  return <div>{children}</div>;
}
import Every from "@/components/every";

export default function Page() {
  return (
    <>
      <Every>1</Every>
    </>
  );
}
it is
I see loading... every page changed
@Ray I see `loading...` every page changed
SilverOP
that is separate. please add the console.log('executed') to the async function and you will see it is not running every time
have you ever tried the code? or just asking?
@Ray have you ever tried the code? or just asking?
SilverOP
i am using the code right now. and it does not execute every time for me
that is why i am confused
can you show your code
and do you see loading... on page change
a post request is made on navigation
SilverOP
huh i found the issue... and it is so dumb lol. so if i add the AuthWrapper.jsx directly to my DashboardWrapper.jsx instead of the individual page.jsx then it does not execute every time. I was trying to prevent having to redefine the AuthWrapper. So i guess if you add a component inside another component it is cache. that is annoying... i wonder if there is a solution @Ray
all you need is wrap the page component
it can't be cache just a client side fetching inside useEffect
but you have to wrap every page which was template doing for you
@Ray but you have to wrap every page which was template doing for you
SilverOP
I guess so. thanks for the assist
@Ray yea there is still a 30 sec router cache with <Link prefetch={false} />
Audubon's Oriole
I don't think there is 30sec cache for Link tag. It is refetching data when user clicks on Link tag
Audubon's Oriole
so Link & router.push has same cache 30sec right?
yes 30sec for dynamic page and 5min for static page
Audubon's Oriole
so what is way to get fresh data?
Audubon's Oriole
I am revalidating data but when I go to that page using router.push then only I get new data. Browser back/forward button not giving me fresh data
how do you revalidate the data
I think you should create a thread
@Ray yes 30sec for dynamic page and 5min for static page
Audubon's Oriole
yes but when I click on Link tag its calling my server function. I am getting consoles
@Ray how do you revalidate the data
Audubon's Oriole
using revalidatetag/revalidatepath
please create a thread and show more detail
Audubon's Oriole
okay
Audubon's Oriole
@Ray I have created thred. Please look into my scenario
I have list of stocks on homepage. When I click on any stocks its taking user's to its details page. Details page data are dynamic and changes every seconds. Problem is when i redirect to stock details page its showing me stale data rather than showing me fresh as I have used export const dynamic = 'force-dynamic'