Problem with dynamic import
Unanswered
Bee posted this in #help-forum
BeeOP
I wrote the following component:
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
"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...😪
Are you using vanilla js or another language code somewhere
@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?
I may be wrong... But will Suspense work for client components?
I don't see console.log anywhere. Suspense doesn't work.
"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.
@Dutch no you will wrap your client components in suspense in server components like
<Suspense fallback={<div>Loading... ...}
<ClientComponent
</Suspense>
BeeOP
Okay! I need to try it. I'll definitely write what happened.