Stop server rendering of client components after a certain point
Unanswered
Sun bear posted this in #help-forum
Sun bearOP
Is there a common way to basically tell Next "past this point don't attempt to render this subtree on the server" ? If I have parts of my page that rely on window or other browser APIs I don't want to have them rendering there.
45 Replies
You can use "client-only" directive or ssr:false
Sun bearOP
what are those?
Method #1
if you put "client-only" at the top of the file, it wont prerender on server
Method #2
import dynamic from 'next/dynamic'
const Component = dynamic(() => import('./somewhere'), { ssr:false })
function MyButton() {
return <Component />
}
if you put "client-only" at the top of the file, it wont prerender on server
Method #2
import dynamic from 'next/dynamic'
const Component = dynamic(() => import('./somewhere'), { ssr:false })
function MyButton() {
return <Component />
}
Sun bearOP
are there any docs for the "client-only" thing? I cant find it anywhere
nope, its a npm package but it works on next, no need to install it
Sun bearOP
oh you're talking about the package you have to import? I dont think that stops SSR it just makes sure it's only been imported inside the clientside bundle, which is still executed on the server
Siamese Crocodile
@Sun bear
Explain what you want
components relying on window apis still work
next just prerenders them on the server
and after hydration they work just fine
Sun bearOP
there's no window object on the server so if something about the window is evaluated during pre-rendering then it will fail
or localstorage is another example
Siamese Crocodile
but you are calling top level window?
then yes
then do
typeof window !== undefined
or
use dynamic import
then they wont be prerendered
Sun bearOP
like I have components that do
useState(localStorage.get('something'))
Siamese Crocodile
yeah so you can initialize it to null and then set a state in useEffect
or use dynamic import
Sun bearOP
yeah I also came across doing something like this
export const ClientsideOnly = ({ children }: { children: React.ReactNode }) => {
const [isClient, setIsClient] = useState(false)
useEffect(() => {
setIsClient(true)
}, [])
return isClient ? children : null
}
yeah the useEffect solution
I think I like this more cuz it doesnt require me to muck around with imports it just shows directly in the JSX tree where the boundary is
Siamese Crocodile
or I am not sure but smth like this should also work
useState(typeof window !== && localstorage.get('something')
nah this client code only component doesn't look good tbh
it would be easier to just use dynamic import ssr false
const ComponentC = dynamic(() => import('../components/C'), { ssr: false })
Sun bearOP
another thing I like aobut the component version is that it lets you make components that self-export the fact that they shouldnt run on the server
like having it export itself wrapped in ClientsideOnly
with dynamic imports you'd have to make two files and re-export from the client-only one with a dynamic import in order to do that
Siamese Crocodile
no
I wouldnt listen to this client-only advice
Its not needed at all
Sun bearOP
like the idea of having a component opt out of pre-rendering?
Siamese Crocodile
const ComponentC = dynamic(() => import('../components/C'), { ssr: false })
This one
SSR false
makes it not prerender on the server
Sun bearOP
yeah I get that but say you make a reusable component like <Graph> and you want to make sure that anywhere its imported and rendered in the app it'll always opt out of prefetching. With the dynamic import approach you're bleeding implementation details of the component by making everyone that uses it have to import it dynamically
Siamese Crocodile
yes thats right you would have to import it dynamically
if thats your case go on and do a reusable one
Sun bearOP
yeah ill use what makes sense I guess now that I know about multiple options. Thanks
next/dynamic
with ssr: false
or client-only
npm should solve your problem