Cannot use ant layout slider collapsable with SSR with NextJs

Viewed 354

I'm using antd within my NextJs app. I placed a Layout component at the top level of my app.

/* _app.tsx */
function MyApp({ Component, pageProps }: AppProps) {
  return (
    <Provider store={store}>
      <SideMenuLayout>
        <div>Patate</div>
      </SideMenuLayout>
    </Provider>
  );
}

/* sideMenuLayout.tsx */
const SideMenuLayout = ({ children }: SideMenuLayoutProps) => {
  const [collapsed, setCollapsed] = useState(false);
  const { Sider } = Layout;

  return (
    <Layout style={{ minHeight: "100vh" }}>
      <Sider collapsible collapsed={collapsed} onCollapse={setCollapsed}>
        <div className="logo" />
        <Menu theme="dark" defaultSelectedKeys={["1"]} mode="inline">
          <Menu.Item key="2" icon={<DesktopOutlined />}>
            Play
          </Menu.Item>
        </Menu>
      </Sider>
      <Layout className="site-layout">{children}</Layout>
    </Layout>
  );
};

I get the error "Warning: useLayoutEffect does nothing on the server".

I understand <sider collapsible... use this useLayoutEffect. I don't understand why default mode is SSR in my case. I'm not sure how I should proceed if I wanna keep the sider collapsable.

Thanks!

3 Answers

Replace component

Try to wrap antd Slider component with condition check, if it is browser pass antd slider otherwise a mocked one. Ideally, you should match the HTML structure of the Slider component with your fake slider.

import {Sider as AntSlider} = from 'antd'

export const Sider = props => (
  typeof window === `undefined`
    ? <div {...props}/>
    : <AntSlider {...props}/>
)

By default, Next.js attempts to pre-render your pages, useEffect is an indicator of client-side code.

However, is interesting how useLayoutEffect is notified as a warning without more details. Since it is omitted on the server pre-render as useEffect is, having this call skipped on the server-side may affect the pre-rendered version of the component. For example, the absolute positioning of an element in the center of a screen depends on screen size, and will not produce the desired result via pre-render.

Perhaps, indicating that your component is dynamic, and not to be considered during the pre-render phase from the get-go is the way-to-go:

import dynamic from "next/dynamic";
const NossrSider = dynamic(() => {
   const [collapsed, setCollapsed] = useState(false);
   const { Sider } = Layout;
   return <Sider collapsible collapsed={collapsed} onCollapse={setCollapsed}>
        <div className="logo" />
        <Menu theme="dark" defaultSelectedKeys={["1"]} mode="inline">
          <Menu.Item key="2" icon={<DesktopOutlined />}>
            Play
          </Menu.Item>
        </Menu>
      </Sider>
},
 {ssr: false}
);
Related