visgl / react-google-maps

React components and hooks for the Google Maps JavaScript API
https://visgl.github.io/react-google-maps/
MIT License
1.31k stars 110 forks source link

[Bug] Warning: useLayoutEffect does nothing on the server #381

Open adrenaline681 opened 6 months ago

adrenaline681 commented 6 months ago

Description

After installing the react-google-maps package we started getting the following error:

Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format. This will lead to a mismatch between the initial, non-hydrated UI and the intended UI. To avoid this, useLayoutEffect should only be used in components that render exclusively on the client. See https://reactjs.org/link/uselayouteffect-ssr for common fixes.
2024-05-24T18:49:02.004220106Z     at Map (file:///app/node_modules/@vis.gl/react-google-maps/dist/index.modern.mjs:805:5)

In our own project we used something like this to prevent this warning issue. const useIsomorphicLayoutEffect = typeof window === 'undefined' ? React.useEffect : React.useLayoutEffect

This means that it will use useLayoutEffect normally, but during Server Side Rendering it will use useEffect

Steps to Reproduce

Use react-google-maps inside of a NextJS project.

Environment

Logs

Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format. This will lead to a mismatch between the initial, non-hydrated UI and the intended UI. To avoid this, useLayoutEffect should only be used in components that render exclusively on the client. See https://reactjs.org/link/uselayouteffect-ssr for common fixes.
2024-05-24T18:49:02.004220106Z     at Map (file:///app/node_modules/@vis.gl/react-google-maps/dist/index.modern.mjs:805:5)
usefulthink commented 6 months ago

We certainly don't want to trigger these warnings when rendering on the server, but I'm trying to figure out what would be the best way to do that.

The suggested solution (useIsomorphicLayoutEffect()) doesn't feel like a good choice – it's just pretending not to use useLayoutEffect when in fact it will use it when it counts. This can lead to problems (not in our case since we're not modifying the DOM, more in general).

In case of our Map component which is triggering the warning, I have two thoughts:

kevinjavitz commented 6 months ago

Having the same issue

For a temporary fix where do I put that code?

const useIsomorphicLayoutEffect = typeof window === 'undefined' ? React.useEffect : React.useLayoutEffect All the warnings make it difficult to read the console.logs when debugging

I am using Remix so I guess it's rendering something server side

Error message:

 Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format. This will lead to a mismatch between the 
initial, non-hydrated UI and the intended UI. To avoid this, useLayoutEffect should only be used in components that render exclusively on the client. See https://reactjs.org/link/uselayouteffect-ssr 
for common fixes.
10:58:14 │ remix      │     at Map (file:///home/kjavitz/Learning/routing/node_modules/@vis.gl/react-google-maps/dist/index.modern.mjs:805:5)
10:58:14 │ remix      │     at MapWrapper (/home/kjavitz/Learning/routing/app/components/mapwrapper.jsx:18:69)
10:58:14 │ remix      │     at APIProvider (file:///home/kjavitz/Learning/routing/node_modules/@vis.gl/react-google-maps/dist/index.modern.mjs:286:7)
usefulthink commented 6 months ago

I've seen this recommended several times, mostly related to unit-testing, but you could give this a shot: Somewhere in the code that exclusively runs on the server (no Idea how that works with remix, sorry), you could add this code that disables the useLayoutEffect hook entirely:

import React from 'react';

React.useLayoutEffect = React.useEffect;

Let me know if that works.

shuuji3 commented 6 months ago

For Remix, I don't have much experience with Remix either, but maybe you can use the client module setting to avoid server rendering if you haven't tried it yet.

Server vs. Client Code Execution | Remix - https://remix.run/docs/en/main/discussion/server-vs-client#splitting-up-client-and-server-code

pgmccullough commented 2 months ago

For Remix, I don't have much experience with Remix either, but maybe you can use the client module setting to avoid server rendering if you haven't tried it yet.

Server vs. Client Code Execution | Remix - https://remix.run/docs/en/main/discussion/server-vs-client#splitting-up-client-and-server-code

For Remix you could also just implement a useEffect to make sure it doesn't hit the server. Something like:

const [ shouldRender, setShouldRender ] = useState(false);

useEffect(() => {
    setShouldRender(true)
},[])

return (
    shouldRender ? (
        <Map... >
            ...
        </Map>
    ) : (
        <>Loading Map...</>
    )
)
asivaneswaran commented 1 month ago

Any updates on how to fix this?

RicardoAALL commented 4 weeks ago

Any updates?

usefulthink commented 4 weeks ago

For now the recommendation is just "avoid rendering components that don't do anything on the server as server-components" (we will probably come up with something better at some point). If anyone here has experience with browser-only components in next.js and remix, let me know how we could improve this.