darkroomengineering / lenis

How smooth scroll should be
https://lenis.darkroom.engineering
MIT License
7.33k stars 316 forks source link

ReactLenis begins halfway down the page on navigation in NextJS 14 with app router #319

Closed cini9 closed 3 months ago

cini9 commented 3 months ago

I'm using react-lenis in my NextJS 14 app using the app router and server components. I have noticed that if I click a Link when Lenis has not come to a complete stop, the next page is scrolled some way down instead of at the top.

When Lenis has completely stopped scrolling, and then I click the link, it works as expected and the new page starts with the scrollbar at the top.

You can see the reproduction here.

Some workarounds that I have come across on the net use the useEffect hook at the top of every page to scroll the top when the page is loaded. This is far from ideal, as I would need to convert all pages to client pages and opt out of server components.

Is this a bug or is this the intended functionality of lenis ? If it is intended, is there any way to "deactivate" lenis on route change and then "activate" it again when the new page renders ?

clementroche commented 3 months ago

Are you recreating new Lenis on every page ?

cini9 commented 3 months ago

No I have it wrapped around the children in the layout

<html lang={lng} className={ppNeueMontreal.variable}>
  <body>
    <NextIntlClientProvider locale={lng} messages={messages}>
      <SmoothScroll>
        <Navbar />
        <Box overflowX='hidden'>{children}</Box>
        <Footer />
        <Consent />
      </SmoothScroll>
    </NextIntlClientProvider>
  </body>
</html>
const SmoothScroll: FC<PropsWithChildren> = ({ children }) => (
  <ReactLenis
    root
    option={{
      duration: 2,
    }}
  >
    {children}
  </ReactLenis>
)
clementroche commented 3 months ago

Any particular reason why you did that way ?

Take a look at how we use lenis in Next.js App context, we usually initialize a new Lenis on every page change https://github.com/darkroomengineering/satus/blob/main/app/(pages)/wrapper/index.js

cini9 commented 3 months ago

The file doesn't seem to exist. But I think I get the concept. I need to create a wrapper component which contains an instance of Lenis and import the wrapper component on all of my pages ?

EDIT : I tried wrapping all of my pages with the component containing Lenis shown below :

const SmoothScroll: FC<PropsWithChildren> = ({ children }) => (
  <>
    <ReactLenis
      root
      option={{
        duration: 2,
      }}
    />
    <Box>{children}</Box>
  </>
)

I am still getting the effect where if Lenis has not come to a complete stop, the next page is rendered scrolled partially down.

clementroche commented 3 months ago

https://github.com/darkroomengineering/satus/blob/main/app/(pages)/(components)/wrapper/index.js

cini9 commented 3 months ago

Yep I based my code on that. Still having this phenomenon occur

clementroche commented 3 months ago

I think you're implementation is wrong since it works as expected on Satus, meaning it's not a lenis issue. I'm closing this issue, can you share a codesandbox ?

cini9 commented 3 months ago

I can setup a codesandbox to check yes. I will add it to this comment when I am done. In the meantime is there a deployed version of satus somewhere ?

clementroche commented 3 months ago

https://satus.darkroom.engineering/

You can't see it there but I tested it on local and works as expected

cini9 commented 3 months ago

Alright I'll check it out and try to a codepen with a reproduction of the issue on my side. Were you able to see the phenomenon on the link that I provided in the original issue ?

UPDATE : I can't seem to reproduce this effect in a basic stackblitz. I'm guessing there is another effect either from gsap or somewhere else that is causing this phenomenon. In the meantime, I modified the lerp to reduce the time it takes to come to a complete stop to mitigate the risk. If anybody else is experiencing this issue and has found the cause, I would love to hear it !

Thanks @clementroche for your support.

clementroche commented 3 months ago

I'm able to see it on your link but it depends on your implementation, it works on Satus