88

Is it possible to disable ssr on some pages using Next js? For example, I have a page with a product description on which I use ssr for SEO but I also have a page with a list of items or products which I can filter and for that page, I don't want to use ssr because this page generates dynamically every time, how can I disable ssr on this page?

gigs
  • 1,241
  • 2
  • 15
  • 25
  • if you use material ui, there is a `NoSsr` component you can use directly out of the box – guest Nov 03 '21 at 06:59

9 Answers9

133

The dynamic() function can also be used without a dynamic import:

// components/NoSsr.jsx

import dynamic from 'next/dynamic'
import React from 'react'

const NoSsr = props => (
  <React.Fragment>{props.children}</React.Fragment>
)

export default dynamic(() => Promise.resolve(NoSsr), {
  ssr: false
})

Anything wrapped in this component will not be visible in the SSR source. For example:

// inside the page you want to disable SSR for

import NoSsr from "components/NoSsr";

Contact me at <NoSsr>email@example.com</NoSsr>
fredrivett
  • 5,419
  • 3
  • 35
  • 48
Erik Hofer
  • 2,296
  • 2
  • 18
  • 39
  • 2
    Works great, can be used to wrap in _app.js for debugging – AveryFreeman Aug 19 '20 at 21:09
  • 3
    Excellent because you can use it with `_app` as well. – Eric Burel Feb 18 '21 at 09:49
  • One limitation though: it probably have other side effects regarding the way code is loaded. A pure React solution might be sufficient (as described in anwser https://stackoverflow.com/a/57512843/5513532 for instance) – Eric Burel Feb 18 '21 at 09:55
125

Lazy load the component and disable SSR: https://nextjs.org/docs/advanced-features/dynamic-import#with-no-ssr

import dynamic from 'next/dynamic'

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

export default () => <DynamicComponentWithNoSSR />
giggi__
  • 1,793
  • 1
  • 11
  • 12
47

This will disable next.js SSR, put this on your _app.tsx

import type { AppProps } from "next/app";
import dynamic from "next/dynamic";
import React from "react";

const App = ({ Component, pageProps }: AppProps) => {
  return <Component {...pageProps} />;
};

export default dynamic(() => Promise.resolve(App), {
  ssr: false,
});
Rizky Ramadhan
  • 7,360
  • 4
  • 27
  • 31
12

This is a late answer, but in case anyone runs into this:

const isServer = () => typeof window === `undefined`;

const Page = () => isServer() ? null : (

  <> 
      <YourClientSideComponent />
  </>
);

This is on the "page" level. isServer() prevents rendering of anything while on the server side. You could, if you wanted to, prevent ssr on the component level also:

const isServer = () => typeof window === `undefined`;

const Page = () =>(

  <> 
      { !isServer() && <YourClientSideComponent /> }
  </>
);
Jacob Sievers
  • 506
  • 4
  • 13
Semur Nabiev
  • 792
  • 5
  • 14
  • 27
  • Is the "." before `!isServer` intentional? That is invalid JavaScript syntax. – Dawson B Jan 20 '20 at 02:56
  • I had it working in the Next.js project with styled-components in it, but doesn't work always as required. Not sure why!! The accepted solution is best fit – Vaishak Mar 13 '20 at 07:35
  • 3
    This will create a mismatch between server-render and client-render, this doesn't actually disable the render. – Eric Burel Feb 18 '21 at 09:50
3

We can also use react-no-ssr React component.

Let's say Comments is our client only component. Now we need to render it only on the client. Here's how we do it.

import React from 'react';
import NoSSR from 'react-no-ssr';
import Comments from './comments.jsx';

const MyPage = () => (
  <div>
    <h2>My Blog Post</h2>
    <hr />
    <NoSSR>
      <Comments />
    </NoSSR>
  </div>
);
refactor
  • 13,954
  • 24
  • 68
  • 103
2

Here's a solution that i just came up with based on the something mentioned in the React docs: https://reactjs.org/docs/react-dom.html#hydrate

class ClientOnly extends React.Component {
  state = {
    isClient: false,
  };

  componentDidMount() {
    this.setState({
      isClient: true,
    });
  }

  render() {
    const { isClient } = this.state;
    const { children } = this.props;

    return isClient ? children : false;
  }
}

You can then wrap any component / block with this and it won't get rendered on the server. e.g.

<ClientOnly>You're logged in as {name}</ClientOnly>

This also prevents the following React.hydrate warning "Warning: Expected server HTML to contain a matching in ."

mikemaccana
  • 110,530
  • 99
  • 389
  • 494
Liam
  • 95
  • 1
  • 5
  • 1
    Equivalent with hooks would look like this I think: `const useClientCheck =() => { const [isClient, setIsClient] = useState(false); useEffect(() => { setIsClient(true)}, []); return isClient }` – Eric Burel Feb 18 '21 at 09:51
2

In @refactor answer, the react-no-ssr is not working for some typescript issue.

I just wrote a very simple NoSSR component as below:

import { ReactNode, useEffect, useLayoutEffect, useState } from 'react'

const DefaultOnSSR: React.FC = () => null

export const NoSSR: React.FC<{ children: ReactNode; onSSR?: ReactNode }> = ({ children, onSSR = <DefaultOnSSR /> }) => {
  const [onBrowser, setOnBrowser] = useState(false)
  useLayoutEffect(() => {
    setOnBrowser(true)
  }, [])
  return <>{onBrowser ? children : onSSR}</>
}

and can be used anywhere if you want to avoid SSR like below:

const MyPage = () => (
  <div>
    <h2>My Blog Post</h2>
    <hr />
    <NoSSR>
      <Comments />
    </NoSSR>
  </div>
);
Ron
  • 6,037
  • 4
  • 33
  • 52
  • This solution gave me "Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format." warning – Mahmoud Sep 29 '22 at 08:07
2

Based entirly on the answer by Erik Hofer, you can create an HOC to wrap your pages or other components in.

import dynamic from 'next/dynamic';
import React from 'react';

const withNoSSR = (Component: React.FunctionComponent) => dynamic(
    () => Promise.resolve(Component),
    { ssr: false },
);

export default withNoSSR;

Then use as:

import React from 'react';
import withNoSSR from './withNoSSR';

function SomePage() {
    return (
        <div>Only renders in the browser</div>
    );
}

// wrap with HOC on export
export default withNoSSR(SomePage);
Sean256
  • 2,849
  • 4
  • 30
  • 39
1

Another and I believe the simplest solution is to just use process.browser, which will only be true when ran on client side.

<div>
  {
    process.browser && <Hidden />
  }
</div>
koral
  • 525
  • 7
  • 23