Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

useLayoutEffect does nothing on the server #3

Closed
estevanmaito opened this issue Jul 1, 2020 · 7 comments
Closed

useLayoutEffect does nothing on the server #3

estevanmaito opened this issue Jul 1, 2020 · 7 comments

Comments

@estevanmaito
Copy link
Owner

windmill-react-ui version: 0.1.0-alpha.8

Relevant code or config:

import React from 'react'
import '../css/tailwind.css'
import { Windmill } from 'windmill-react-ui'

function MyApp({ Component, pageProps }) {
  return (
    <Windmill>
      <Component {...pageProps} />
    </Windmill>
  )
}

export default MyApp

What you did:

Rendered Windmill component with NextJS

What happened:

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://fb.me/react-uselayouteffect-ssr for common fixes.

Reproduction:

Docs repo of this project (not available yet)

@estevanmaito estevanmaito added the bug Something isn't working label Jul 1, 2020
@estevanmaito
Copy link
Owner Author

Need to dig a little more into this, but:

  1. It's just a warning
  2. It's probably related to the useLayoutEffect that is responsible for the theme. If that is the case, then it's not solvable with useEffect, as the layout here is needed to avoid a flash of light theme when the user actually prefers dark, which is stored in localStorage (client only) and should run as soon as possible.

Will keep it open to remind me.

@ronyfhebrian
Copy link

Hi! what is the solution for useLayoutEffect bug?
Thank you.

@estevanmaito estevanmaito removed the bug Something isn't working label Nov 13, 2020
@estevanmaito
Copy link
Owner Author

@ronyfhebrian Please, refer to the comment above yours. It's a warning and it's needed to render the component only on client.

@franz-fletcher
Copy link

A mismatch in server rendered UI and client side UI is a potential dealbreaker for us folks using Styled JSX but since wrapping the app in the <Windmill/> does not stop us from using the packaged components. Following the This handy article, you can create your own app wrapper component and theme file to modify component styles as needed using Windmill's theme defaults as reference.

Not ideal, we're out here in the tailwind v2 and React 17 world. Still a handy UI library though. Appreciate your work!

@mattgi
Copy link

mattgi commented Jan 10, 2021

This was a workaround to get things going on nextjs

components/render-where.tsx

import React, { useEffect, useState } from "react";

export const RenderWhere: React.FC<{ client?: boolean; server?: boolean }> = (props) => {
  const [isMounted, setIsMounted] = useState(false);

  useEffect(() => setIsMounted(true), []);

  if (!isMounted && props.client) {
    return null;
  }

  if (isMounted && props.server) {
    return null;
  }

  return props.children as React.ReactElement;
};

pages/_app.tsx

import "../styles/tailwind.css";

import { Windmill } from "@windmill/react-ui";
import { AppProps } from "next/app";
import Head from "next/head";
import * as React from "react";

import { RenderWhere } from "../components/render-where";

export default function App({ Component, pageProps }: AppProps): JSX.Element {
  return (
    <>
      <Head>
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>App</title>
      </Head>
      <RenderWhere server>
        <Component {...pageProps} />
      </RenderWhere>
      <RenderWhere client>
        <Windmill>
          <Component {...pageProps} />
        </Windmill>
      </RenderWhere>
    </>
  );
}

@cassus
Copy link

cassus commented Mar 11, 2021

The RenderWhere workaround re-renders the whole page after hydration. Form element loose their state in this case so this is not ideal.

@estevanmaito would you consider using useBrowserLayoutEffect ?

It avoids the warning for SSR:

const useBrowserLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : () => {}

Example usage: https://github.com/dhovart/next10-intl/blob/4638d3dc91eee4a7f35b8d056c74fdf126ea9f85/src/context/Next10IntlProvider.tsx
Similar use in Redux: https://github.com/reduxjs/react-redux/blob/d16262582b2eeb62c05313fca3eb59dc0b395955/src/components/connectAdvanced.js#L40

@mrofi
Copy link

mrofi commented Dec 4, 2021

This comment works for me.

https://gist.github.com/gaearon/e7d97cdf38a2907924ea12e4ebdf3c85#gistcomment-3886909

Just put this in pages/_app.js or some other top-level place:

// suppress useLayoutEffect warnings when running outside a browser
if (!process.browser) React.useLayoutEffect = React.useEffect;

useLayoutEffect and useEffect have the same argument signature, and neither runs if we're not in a browser.
So if we're not in a browser it's safe to globally replace the one that triggers warnings with the one that doesn't.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants