atlassian / react-beautiful-dnd

Beautiful and accessible drag and drop for lists with React
https://react-beautiful-dnd.netlify.app
Other
33.4k stars 2.58k forks source link

Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format. #1259

Closed trevorpfiz closed 5 years ago

trevorpfiz commented 5 years ago

Expected behavior

I would expect there to be no warning. I may be missing a step to get this to work correctly.

Actual behavior

Gives "Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format."

Steps to reproduce

Use the library with Next.js

Suggested solution?

Is there a way to fix/silence the warnings?

What version of React are you using?

16.8.5

What version of react-beautiful-dnd are you running?

11.0.0

What browser are you using?

Chrome

Demo

alexreardon commented 5 years ago

Interesting. We currently do a lame hack to get around useLayoutEffect SSR warnings.

I suspect that next.js is setting up a window 🤔

alexreardon commented 5 years ago

We avoid using useLayoutEffect in node environments for this reason. However, it looks like something going on in next might be circumventing our logic.

alexreardon commented 5 years ago

I have tested next and I cannot reproduce the issue. I even checked a production build

https://github.com/alexreardon/nextjs-rbd

bensalilijames commented 5 years ago

I'm experiencing this though I think it's a result of an unrelated problem to react-beautiful-dnd.

In our case, the warning appears when changing pages, but not on the server-side render. This initially sounds really weird (why is there a SSR warning on a client render?).

The answer lies in the fact that we're using react-apollo alongside next.js.

Page changes cause getDataFromTree from react-apollo to run, which calls:

require("react-dom/server").renderToStaticMarkup

So even though the rendering is running on the client, it runs a "server" render, which I think results in the warning.

Though of course this doesn't explain any behaviour that isn't linked to react-apollo (not sure what @ElektrikSpark's setup is!) 🙂

alexreardon commented 5 years ago

I'll close this for now. Please let me know if you think there is anything we should be doing

robertcoopercode commented 5 years ago

Just pitching in that I'm experiencing the same console error. Like @benhjames, I'm using NextJS and react-apollo and the error triggers on page change.

Only thought to look in this repo as the stack trace points be to the Draggable component

image

Wish I could contribute more to the conversation :S

trevorpfiz commented 5 years ago

I am using Next.js and react-apollo/react-apollo-hooks as well. Guess I just didn't notice the error until I implemented react-beautiful-dnd?

alexreardon commented 5 years ago

it looks like our useLayoutEffect / useLayout SSR swap logic is not working in react-apollo. Have you come across this @markerikson?

markerikson commented 5 years ago

Per that comment earlier, it sounds as if they're using ReactDOMServer.renderToStarticMarkup() on the client side (which I've seen done a few times). That SSR implementation is what contains the useLayoutEffect warning. It would normally be running under Node, in which case the "does window exist" check be false and fall back to useEffect. But, since this is A) SSR code that warns, and B) running in a browser environment where window does exist, you end up with an actual attempt to call useLayoutEffect, which ends up warning.

alexreardon commented 5 years ago

Aye. Thanks @markerikson. It is painful that useLayoutEffect logs an SSR warning..

https://github.com/facebook/react/issues/14927

akosbeke commented 5 years ago

For those who run into this problem with next and react-apollo:

With the next-with-apollo package I experienced this issue but then I refactored my apollo client initialization based on the official Next.js repo:

https://github.com/zeit/next.js/tree/canary/examples/with-apollo

Now it works perfectly without throwing the warning messages.

TLevesque commented 4 years ago

Thank you @akosbeke for your solution with the apollo config, it is fixing the "useLayoutEffect" error message. But, there is still a problem which persists on the first render of a React Beautiful DnD component, which displays the following error message for each draggable element:

"react-beautiful-dnd A setup problem was encountered.> Invariant failed: Draggable[id: item-0]: Unable to find drag handle"

To reproduce this bug I've created the following repo: https://github.com/TLevesque/Nextjs-Apollo-React-Beautiful-DnD which is just the combination of your repo from Nextjs examples with the apollo config and Nextjs https://github.com/zeit/next.js/tree/canary/examples/api-routes-apollo-server-and-client and the one of @alexreardon https://github.com/alexreardon/nextjs-rbd he has made for a test with Nextjs.

I've modified nothing into the code of each repository, just imported the Alex' component into nextjs example repo. Apparently, switching from dynamic page to static, make the DnD elements working again, but I've no clue about how to make it work on the first render, any idea?

Thanks

alexreardon commented 4 years ago

Let me know if you want any input @akosbeke. Here is how we are getting around the issue: https://medium.com/@alexandereardon/uselayouteffect-and-ssr-192986cdcf7a

akosbeke commented 4 years ago

Hey @TLevesque,

Well I've spent some time with your example repo and I spotted that there are version differences in the package.json files.

In theory you shouldn't occur any problems due to thereact-apollo integration since your /about page does not use the withApollo HOC.

I went ahead and changed the package.json file of the /alexreardon/nextjs-rbd repo and updated the react-beautiful-dnd package to 12.1.1 (like in your example) and it started to show the same error at first renders (which is SSR). Also your test repo should work with version ^11.0.0 of react-beautiful-dnd.

At this point I have no idea what causes the error but I am pretty sure it has nothing to do with react-apollo. Looks like the bug has been introduced with some of the updates of the react-beautiful-dnd package and it is related to NextJS or SSR in general somehow.

@alexreardon does this - by any chance - ring a bell?

It might not be related but there is a warning message as well about the server and client context IDs being different. And the server context id is increased by one with every hard page refresh (the client id always remains "0").

Warning: Propdata-rbd-draggable-context-iddid not match. Server: "2" Client: "0"

JClackett commented 4 years ago

Using Next.js with rb-dnd. On inital page load i.e. server rendered, i get:

Unable to find any drag handles in the context "0"

It's then unresponsive

However if navigation to the page that uses it ,i.e. client rendered, it works as expected, any idea?

eddyw commented 4 years ago

@akosbeke

It might not be related but there is a warning message as well about the server and client context IDs being different. And the server context id is increased by one with every hard page refresh (the client id always remains "0").

Warning: Propdata-rbd-draggable-context-iddid not match. Server: "2" Client: "0"

I don't think it's related at all to the current issue. However, I found this thread trying to find a solution to the warning 🙈 , so, according to this: https://github.com/atlassian/react-beautiful-dnd/blob/master/docs/api/reset-server-context.md

I solved it by adding resetServerContext() in pages/_document.tsx

kyle-mccarthy commented 4 years ago

@eddyw where exactly did you include it in your pages/_document.tsx? I added it but still get:

"Warning: Prop data-react-beautiful-dnd-draggable did not match. Server: "7" Client: "0"

// ...
import { resetServerContext } from 'react-beautiful-dnd';

resetServerContext();

export default class MyDocument extends Document {
// ...

update: this is how it is supposed to be done https://github.com/atlassian/react-beautiful-dnd/issues/436

If you are still having this issue and you are using a package that has react-beautiful-dnd as a dependency, you are probably resetting the server context on the wrong module instance.

eddyw commented 4 years ago

@kyle-mccarthy yeah, my solution was similar. If you actually need to overwrite the ctx.renderPage, then you can also put it there. Otherwise just keep it simple:

CustomDocument.getInitialProps = async (ctx) => {
  resetServerContext()
  return Document.getInitialProps(ctx)
}