Next.js Discord

Discord Forum

Problem with dynamic import

Unanswered
Bee posted this in #help-forum
Open in Discord
BeeOP
I wrote the following component:

"use client"

import { usePathname } from "next/navigation";
import dynamic from "next/dynamic";
import Logo from "@/components/Logo";
import NavLink from "@/components/header/Navigation/NavLink";
import { NavigationItem } from "@/components/header/Navigation/navigation.dao";
import SkeletonShoppingBag from "@/components/header/Navigation/ShoppingBag/SkeletonShoppingBag";
import SkeletonMobileMenu from "@/components/header/Navigation/MobileMenu/SkeletonMobileMenu";

const ShoppingBagWrapper = dynamic(() => import('@/components/header/Navigation/ShoppingBag/ShoppingBagWithStore'), {
    loading: () => <SkeletonShoppingBag />, // Works correctly
    ssr: false // The server leaves an error in view-source. For some reason the server is trying to render...
});

const MobileMenuWrapper = dynamic(() => import('@/components/header/Navigation/MobileMenu/MobileMenuWithStore'), {
    loading: () => <SkeletonMobileMenu /> // It doesn't work correctly
    // No error
});

const Navigation = () => {

    const pathname = usePathname()

    const navigation: NavigationItem[] = [
        { name: 'Shop', href: '/', current: pathname === "/" },
        { name: 'About us', href: '/about-us', current: pathname === '/about-us' || pathname.startsWith('/about-us/') },
    ]

    return (
        <div className='container mx-auto sm:py-6 py-4 md:px-2 px-4'>
            <div className="flex w-full items-center justify-between">
                <Logo />
                <div className='flex items-center'>
                    <nav className="hidden sm:ml-6 sm:block">
                        <ul className="flex space-x-4">
                            {navigation.map((item) => (
                                <NavLink key={item.name} item={item}/>
                            ))}
                        </ul>
                    </nav>
                    <div className="flex items-center min-w-12 sm:static sm:inset-auto sm:ml-6 sm:pr-0">
                        <ShoppingBagWrapper />
                        <MobileMenuWrapper navigation={navigation} />
                    </div>
                </div>
            </div>
        </div>
    );
};

export default Navigation;


The first import variant works fine on the client without any errors. But if you open the view-source, there's an error:
"Bail out to client-side rendering: next/dynamic" data-stck="Switched to client rendering because the server rendering errored
...

The second variant doesn't display the Skeleton on the client, but there are no errors in the view-source.

Maybe someone can suggest the correct way to handle this situation?
Is there still a way to force Next to render this component on the client without attempting to render it on the server?😄

Next.js version: 15.3.2

14 Replies

Dutch
if you show the code of that dynamic components
BeeOP
@Dutch Yes of course! Here is the code:

'use client'

import StoreProvider from '@/store/StoreProvider';
import ShoppingBag from './ShoppingBag';

const ShoppingBagWithStore = () => (
    <div aria-busy="false">
        <StoreProvider>
            <ShoppingBag/>
        </StoreProvider>
    </div>
);

export default ShoppingBagWithStore;


"use client"

import StoreProvider from "@/store/StoreProvider";
import MobileMenu from "@/components/header/Navigation/MobileMenu/MobileMenu";
import { MobileMenuProps } from "@/components/header/Navigation/navigation.dao";

const MobileMenuWithStore = ({ navigation } : MobileMenuProps) => {
    return (
        <StoreProvider>
            <MobileMenu navigation={navigation} />
        </StoreProvider>
    );
};

export default MobileMenuWithStore;


'use client'

import { ReactNode } from 'react';
import { Provider } from 'react-redux';
import { PersistGate } from "redux-persist/integration/react";
import store, { persistor } from '@/store/store';

interface StoreProviderProps {
    children: ReactNode;
}

export default function StoreProvider({ children }: StoreProviderProps) {
    return (
        <Provider store={store}>
            <PersistGate loading={null} persistor={persistor}>
                {children}
            </PersistGate>
        </Provider>
    );
}
@Dutch Probably its related with components inside that components
BeeOP
All components there are client-side. But Next tries to render them on the server. When it fails, it renders on the client. Actually, first an error appears in view-source. And then everything renders fine on the client.
Yu need to wrap with suspense that dynamic imported components, but why they are dynamic
@Dutch Yu need to wrap with suspense that dynamic imported components, but why they are dynamic
BeeOP
I tried using Suspense. For some reason, it doesn’t work as expected. The UI starts to jump during the page render. I decided to try dynamic import instead. Ended up with this issue... The only option that works is using aspect in styles — then everything is fine. But I was hoping to make use of the framework’s and React’s capabilities...😪
@Dutch Are you using vanilla js or another language code somewhere
BeeOP
No. I use payloadcms.
@Bee No. I use payloadcms.
Dutch
Use suspense and tell me what happens
@Dutch Use suspense and tell me what happens
BeeOP
Do you mean to do it like this?

"use client"

import { usePathname } from "next/navigation";
import Logo from "@/components/Logo";
import NavLink from "@/components/header/Navigation/NavLink";
import { NavigationItem } from "@/components/header/Navigation/navigation.dao";
import SkeletonShoppingBag from "@/components/header/Navigation/ShoppingBag/SkeletonShoppingBag";
import SkeletonMobileMenu from "@/components/header/Navigation/MobileMenu/SkeletonMobileMenu";
import {Suspense} from "react";
import ShoppingBagWithStore from "@/components/header/Navigation/ShoppingBag/ShoppingBagWithStore";
import MobileMenuWithStore from "@/components/header/Navigation/MobileMenu/MobileMenuWithStore";

const Navigation = () => {

    const pathname = usePathname()

    const navigation: NavigationItem[] = [
        { name: 'Shop', href: '/', current: pathname === "/" },
        { name: 'About us', href: '/about-us', current: pathname === '/about-us' || pathname.startsWith('/about-us/') },
    ]

    return (
        <div className='container mx-auto sm:py-6 py-4 md:px-2 px-4'>
            <div className="flex w-full items-center justify-between">
                <Logo />
                <div className='flex items-center'>
                    <nav className="hidden sm:ml-6 sm:block">
                        <ul className="flex space-x-4">
                            {navigation.map((item) => (
                                <NavLink key={item.name} item={item}/>
                            ))}
                        </ul>
                    </nav>
                    <div className="flex items-center min-w-12 sm:static sm:inset-auto sm:ml-6 sm:pr-0">
                        <Suspense fallback={<SkeletonShoppingBag />}>
                            <ShoppingBagWithStore />
                        </Suspense>
                        <Suspense fallback={<SkeletonMobileMenu />}>
                            <MobileMenuWithStore navigation={navigation}/>
                        </Suspense>
                    </div>
                </div>
            </div>
        </div>
    );
};

export default Navigation;


I may be wrong... But will Suspense work for client components?

const SkeletonMobileMenu = () => {

    console.log("FROM SkeletonMobileMenu !!!!!!!! SkeletonMobileMenu");

    return (
        <div role="status"
             className="sm:hidden w-10 h-10 ml-5 flex flex-col justify-center items-center space-y-1.5 animate-pulse">
            <div className="w-6 h-0.5 bg-[var(--color-grey-main)] rounded"/>
            <div className="w-6 h-0.5 bg-[var(--color-grey-main)] rounded"/>
            <div className="w-6 h-0.5 bg-[var(--color-grey-main)] rounded"/>
            <span className="sr-only">Loading...</span>
        </div>
    )
}      ;

export default SkeletonMobileMenu;


I don't see console.log anywhere. Suspense doesn't work.
@Bee Do you mean to do it like this? javascript "use client" import { usePathname } from "next/navigation"; import Logo from "@/components/Logo"; import NavLink from "@/components/header/Navigation/NavLink"; import { NavigationItem } from "@/components/header/Navigation/navigation.dao"; import SkeletonShoppingBag from "@/components/header/Navigation/ShoppingBag/SkeletonShoppingBag"; import SkeletonMobileMenu from "@/components/header/Navigation/MobileMenu/SkeletonMobileMenu"; import {Suspense} from "react"; import ShoppingBagWithStore from "@/components/header/Navigation/ShoppingBag/ShoppingBagWithStore"; import MobileMenuWithStore from "@/components/header/Navigation/MobileMenu/MobileMenuWithStore"; const Navigation = () => { const pathname = usePathname() const navigation: NavigationItem[] = [ { name: 'Shop', href: '/', current: pathname === "/" }, { name: 'About us', href: '/about-us', current: pathname === '/about-us' || pathname.startsWith('/about-us/') }, ] return ( <div className='container mx-auto sm:py-6 py-4 md:px-2 px-4'> <div className="flex w-full items-center justify-between"> <Logo /> <div className='flex items-center'> <nav className="hidden sm:ml-6 sm:block"> <ul className="flex space-x-4"> {navigation.map((item) => ( <NavLink key={item.name} item={item}/> ))} </ul> </nav> <div className="flex items-center min-w-12 sm:static sm:inset-auto sm:ml-6 sm:pr-0"> <Suspense fallback={<SkeletonShoppingBag />}> <ShoppingBagWithStore /> </Suspense> <Suspense fallback={<SkeletonMobileMenu />}> <MobileMenuWithStore navigation={navigation}/> </Suspense> </div> </div> </div> </div> ); }; export default Navigation; I may be wrong... But will Suspense work for client components? javascript const SkeletonMobileMenu = () => { console.log("FROM SkeletonMobileMenu !!!!!!!! SkeletonMobileMenu"); return ( <div role="status" className="sm:hidden w-10 h-10 ml-5 flex flex-col justify-center items-center space-y-1.5 animate-pulse"> <div className="w-6 h-0.5 bg-[var(--color-grey-main)] rounded"/> <div className="w-6 h-0.5 bg-[var(--color-grey-main)] rounded"/> <div className="w-6 h-0.5 bg-[var(--color-grey-main)] rounded"/> <span className="sr-only">Loading...</span> </div> ) } ; export default SkeletonMobileMenu; I don't see console.log anywhere. Suspense doesn't work.
Dutch
no you will wrap your client components in suspense in server components like
<Suspense fallback={<div>Loading... ...}
<ClientComponent
</Suspense>