Current behavior:

When there is a style that is conditionally applied on the browser, the styles from the server are not changed even though the component runs and the browser props are passed in Correctly. The html sent back from the server stays on the page, and even after the first render on the client where the new browser-based props are passed on, the component continues to display the server styles. This is in a nextjs app, using emotion 11

I feel like this must be covered somewhere, but i combed SO, these issues, and nextjs issues all day and have found nothing describing the exact issue nor a fix for it.

To reproduce: Codesandbox showing a component which has one set of styles on the server, and then when on the browser, should switch to a different set of styles

https://codesandbox.io/s/cool-worker-meil8?file=/package.json:200-335

On the server, the box is rendered red because process.browser is false. On the browser, the isBrowser prop is true, so the box should be blue after the js runs. However, despite the console logs showing that the styled component did in fact run on the client with isBrowser true and the background-color being set as blue, the box remains red (this isn't in the sandbox, but the only way i have found to force the component to actually change color is through client side navigation or some sort of separate forced state update which rerenders the component).

Expected behavior:

I would expect the server to send back the html/styles for the server based version of the component, and then following the first render on the client, the component should read in the browser based styles and update to match the styles based off of the browser props.

Environment information: This codesandbox was built using the base version of nextjs on codesandbox, by the way. I didn't modify anything outside of adding emotion

Here are the deps in the sandbox:

"@emotion/react": "11.4.1"

"@emotion/styled": "11.3.0"

"next": "latest"

"react": "17.0.2"

"react-dom": "17.0.2"

1

There are 1 best solutions below

0
On

It seems this is not an emotion specific issue, but is actually due to the fact that newer versions of react do not diff the dom on hydration, and instead preserve the html while still generating the correct component tree (thus the js runs, leading to my confusion, but the dom is not reconciled to match what the component tree shows it should be).

In case anyone else runs into this, the solution is to use a component like this, which renders one component immediately on the server, and then on the client triggers a render by setting isMounted state in a useLayoutEffect (this will not run/rerender on the server)which then renders the client component. The general idea is shown here:

https://github.com/vercel/next.js/discussions/14469