1

I'm learning Next.js and I'm trying to integrate the @react-aria/overlays package in my project. I have a layout component, where I'm simply invoking the usePreventScroll method like this:

   usePreventScroll({
        isDisabled: true
    });

This layout component is used in my _app.js.

import { useEffect } from 'react'
import { useRouter } from 'next/router'
import * as gtag from '../lib/gtag'

import 'styles/vendor.scss';
import 'styles/globals.scss';

import Layout from 'components/layout';

import { SSRProvider } from '@react-aria/ssr';

const App = ({ Component, pageProps }) => {
  return (
      <SSRProvider>
        <Layout>
          <Component {...pageProps} />
        </Layout>
      </SSRProvider>
  )
}

export default App;

When going to my browser and loading a page, it gives me the following error:

Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format. This will lead to a mismatch between the initial, non-hydrated UI and the intended UI. To avoid this, useLayoutEffect should only be used in components that render exclusively on the client. See https://reactjs.org/link/uselayouteffect-ssr for common fixes.
    at Layout (/home/bas/projects/test-website/build/server/pages/_app.js:718:3)
    at div
    at $c5f9596976ab8bd94c5879001549a3e$var$OverlayContainerDOM (/home/bas/projects/test-website/node_modules/@react-aria/overlays/dist/main.js:864:7)
    at ModalProvider (/home/bas/projects/test-website/node_modules/@react-aria/overlays/dist/main.js:810:5)
    at OverlayProvider
    at SSRProvider (/home/bas/projects/test-website/node_modules/@react-aria/ssr/dist/main.js:33:13)
    at UIContextProvider (/home/bas/projects/test-website/build/server/pages/_app.js:1144:74)
    at ManagedUIContext (/home/bas/projects/test-website/build/server/pages/_app.js:1105:3)
    at App (/home/bas/projects/test-website/build/server/pages/_app.js:5171:3)
    at AppContainer (/home/bas/projects/test-website/node_modules/next/dist/next-server/server/render.js:23:748)

What's the problem here and how would I be able to solve it?

I tried wrapping the the Layout component in the packages <SSRProvider>.

Bas
  • 2,106
  • 5
  • 21
  • 59

2 Answers2

3

You can dynamically load the component and disable SSR:

import dynamic from 'next/dynamic'

const DynamicComponentWithNoSSR = dynamic(
  () => import('../components/hello3'),
  { ssr: false }
)

function Home() {
  return (
    <div>
      <Header />
      <DynamicComponentWithNoSSR />
      <p>HOME PAGE is here!</p>
    </div>
  )
}

export default Home

The code example has been taken from the NextJS docs. If that's not your thing, you can call the hook or render the component as long as processs.browser is true.

CoodleNoodle
  • 324
  • 3
  • 17
  • How would I call the `usePreventScroll` using that? Would I need an extra component? – Bas Oct 31 '20 at 15:11
  • No, you would only call dynamic() when you import/use the component. If you don't want to dynamically import the component just to work around SSR, then render your Layout component conditionally when process.browser is true. – CoodleNoodle Oct 31 '20 at 15:24
1

Next js is computes your 1st page on server. so it does not understand browser scroll or localstorage or other browser api. you can add a check in your code block if window object is present or execution is running in server and then execute usePreventDefault.

    import {useIsSSR} from '@react-aria/ssr';

    function Layout() {
       let isSSR = useIsSSR();
 
       useEffect(() => {
         !isSSR && usePreventScroll({ ... }) 
       }, [isSSR])
    }
Shyam
  • 1,364
  • 7
  • 13
  • I think you ment `usePreventScroll` instead of `usePreventDefault`, but it didn't work out. I got the following error `Error: Rendered more hooks than during the previous render.` – Bas Oct 31 '20 at 14:40
  • Thanks for the help , but with the updated answer it gives me a `Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:` – Bas Oct 31 '20 at 14:55
  • Is it not a functional component? can you share where you are calling the method. – Shyam Oct 31 '20 at 14:57
  • In my `_app.js` . I'll paste the file in. – Bas Oct 31 '20 at 14:59
  • I mean is your layout component, where you are calling `usePreventScroll` is not functional component? – Shyam Oct 31 '20 at 15:02
  • then it must be in componentDidMount, shouldnt re-render. Just add window check without useIsSSR hook. `componentDidMount() { window && usePreventScrolll() }` – Shyam Oct 31 '20 at 15:13
  • I'm sorry, `layout` is actually a functional component. Where it does work properly by checking window. Why can't I use `useIsSSR` in this situation? – Bas Oct 31 '20 at 15:23