NextJS server side renders, which if a library dependencies or requirements, this can mess up how a library operates. One such library is react-beautiful-dnd
. It's become the standard drag and drop library but when integrating into a Next.JS app requires one additional piece. That piece is using resetServerContext
call.
This needs to be called so that markup from the server doesn't conflict with what the client side library expects.
To make it work we need to create a custom _document
file in the pages
directory. You can follow the docs for the base _document
here https://nextjs.org/docs/advanced-features/custom-document
This is what it looks like.
import Document, { Html, Head, Main, NextScript } from "next/document"; class MyDocument extends Document { static async getInitialProps(ctx) { const initialProps = await Document.getInitialProps(ctx); return { ...initialProps }; } render() { return ( <Html> <Head /> <body> <Main /> <NextScript /> </body> </Html> ); } } export default MyDocument;
Then we need to import resetServerContext
from react-beautiful-dnd
and call it in our getInitialProps
before we return.
import { resetServerContext } from "react-beautiful-dnd"; static async getInitialProps(ctx) { const initialProps = await Document.getInitialProps(ctx); resetServerContext() return { ...initialProps } }
This will work great for most cases, however there is another issue if you are running latest Emotion like version 11 or another CSS-in-JS that requires the HTML to extract styling from. This generally requires a call to renderPage
.
Just ensure that you call renderPage
is rendered, first then you call Document.getInitialProps
. If you do not call these in the correct order then you may receive an unable to find any drag handles
from react-beautiful-dnd
and none of your dragging will work.
Unable to find any drag handles in the context "0"
Here is what a complete example of a _document
file with Emotion 11 and resetServerContext
from react-beautiful-dnd
looks like.
import Document, { Html, Head, Main, NextScript } from "next/document"; import { extractCritical } from "@emotion/server"; import { resetServerContext } from "react-beautiful-dnd"; export default class MyDocument extends Document { static async getInitialProps(ctx) { const page = await ctx.renderPage(); const initialProps = await Document.getInitialProps(ctx); const styles = extractCritical(page.html); resetServerContext(); return { ...initialProps, ...page, ...styles }; } render() { return ( <Html lang="en"> <Head> <style data-emotion-css={this.props.ids.join(" ")} dangerouslySetInnerHTML={{ __html: this.props.css }} /> </Head> <body> <Main /> <NextScript /> </body> </Html> ); } }