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

RichText rendering nested li's causing nextjs hydration errors #97

Closed
MaciejWiatr opened this issue Jan 13, 2023 · 2 comments
Closed

RichText rendering nested li's causing nextjs hydration errors #97

MaciejWiatr opened this issue Jan 13, 2023 · 2 comments

Comments

@MaciejWiatr
Copy link

MaciejWiatr commented Jan 13, 2023

Hi, our team relies pretty heavly on both hygraph and this packages and after recent migration to react 18 which is more strict on the valid node nesting it turned out that RichText component is rendering list elements as nested li tags which cause hydration issues in next.

Here's an minimal example using data copied straight from our hygraph:
https://github.com/MaciejWiatr/rich-text-react-renderer-li-issue/blob/main/src/pages/index.tsx
https://rich-text-react-renderer-li-issue.vercel.app/

Screenshots:
image
image
image
Full error messages:

Warning: Expected server HTML to contain a matching 
  • in
  • . li li@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:190:20 RenderElement@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:389:17 RenderNode@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:354:14 RenderElements@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:507:17 list_item_child@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:274:20 RenderElement@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:389:17 RenderNode@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:354:14 RenderElements@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:507:17 li li@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:190:20 RenderElement@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:389:17 RenderNode@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:354:14 RenderElements@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:507:17 ul ul@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:182:20 RenderElement@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:389:17 RenderNode@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:354:14 RenderElements@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:507:17 RichText@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:524:17 div Home App@webpack-internal:///./src/pages/_app.tsx:9:38 PathnameContextProviderAdapter@webpack-internal:///./node_modules/next/dist/shared/lib/router/adapters.js:62:34 ErrorBoundary@webpack-internal:///./node_modules/next/dist/compiled/@next/react-dev-overlay/dist/client.js:301:63 ReactDevOverlay@webpack-internal:///./node_modules/next/dist/compiled/@next/react-dev-overlay/dist/client.js:850:908 Container@webpack-internal:///./node_modules/next/dist/client/index.js:61:1 AppContainer@webpack-internal:///./node_modules/next/dist/client/index.js:171:25 Root@webpack-internal:///./node_modules/next/dist/client/index.js:346:37 [next-dev.js:20:25](webpack://_N_E/node_modules/next/dist/client/next-dev.js?3515) Uncaught Error: Hydration failed because the initial UI does not match what was rendered on the server.

    See more info here: https://nextjs.org/docs/messages/react-hydration-error
    React 12
    workLoop scheduler.development.js:266
    flushWork scheduler.development.js:239
    performWorkUntilDeadline scheduler.development.js:533
    EventHandlerNonNull* scheduler.development.js:571
    scheduler.development.js:633
    NextJS 4
    index.js:6
    NextJS 4
    React 2
    NextJS 4
    React
    NextJS 4
    React
    NextJS 4
    index.js:14
    NextJS 4
    next-dev.js:3
    NextJS 7
    react-dom.development.js:12507
    Warning: An error occurred during hydration. The server HTML was replaced with client content in

    .

    See more info here: https://nextjs.org/docs/messages/react-hydration-error next-dev.js:20:25
    Warning: validateDOMNesting(...):

  • cannot appear as a descendant of
  • .
    li
    li@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:190:20
    RenderElement@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:389:17
    RenderNode@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:354:14
    RenderElements@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:507:17
    list_item_child@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:274:20
    RenderElement@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:389:17
    RenderNode@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:354:14
    RenderElements@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:507:17
    li
    li@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:190:20
    RenderElement@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:389:17
    RenderNode@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:354:14
    RenderElements@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:507:17
    ul
    ul@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:182:20
    RenderElement@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:389:17
    RenderNode@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:354:14
    RenderElements@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:507:17
    RichText@webpack-internal:///./node_modules/@graphcms/rich-text-react-renderer/dist/rich-text-react-renderer.esm.js:524:17
    div
    Home
    App@webpack-internal:///./src/pages/_app.tsx:9:38
    PathnameContextProviderAdapter@webpack-internal:///./node_modules/next/dist/shared/lib/router/adapters.js:62:34
    ErrorBoundary@webpack-internal:///./node_modules/next/dist/compiled/@next/react-dev-overlay/dist/client.js:301:63
    ReactDevOverlay@webpack-internal:///./node_modules/next/dist/compiled/@next/react-dev-overlay/dist/client.js:850:908
    Container@webpack-internal:///./node_modules/next/dist/client/index.js:61:1
    AppContainer@webpack-internal:///./node_modules/next/dist/client/index.js:171:25
    Root@webpack-internal:///./node_modules/next/dist/client/index.js:346:37 next-dev.js:20:25
    Uncaught Error: Hydration failed because the initial UI does not match what was rendered on the server.

    See more info here: https://nextjs.org/docs/messages/react-hydration-error
    React 9
    workLoop scheduler.development.js:266
    flushWork scheduler.development.js:239
    performWorkUntilDeadline scheduler.development.js:533
    EventHandlerNonNull* scheduler.development.js:571
    scheduler.development.js:633
    NextJS 4
    index.js:6
    NextJS 4
    React 2
    NextJS 4
    React
    NextJS 4
    React
    NextJS 4
    index.js:14
    NextJS 4
    next-dev.js:3
    NextJS 7
    7 react-dom.development.js:12507
    Uncaught Error: There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.
    React 8
    workLoop scheduler.development.js:266
    flushWork scheduler.development.js:239
    performWorkUntilDeadline scheduler.development.js:533
    EventHandlerNonNull* scheduler.development.js:571
    scheduler.development.js:633
    NextJS 4
    index.js:6
    NextJS 4
    React 2
    NextJS 4
    React
    NextJS 4
    React
    NextJS 4
    index.js:14
    NextJS 4
    next-dev.js:3
    NextJS 7

  • @jpedroschmitz
    Copy link
    Contributor

    Hey @MaciejWiatr! Thanks for creating such a detailed issue! I'll look into this ASAP.

    @jpedroschmitz
    Copy link
    Contributor

    @MaciejWiatr, I've looked into the issue, and I was able to reproduce it locally following your example.

    The React package (and the other packages) render precisely what you provide as content to it, and looking at your content, you can see that you have nested li inside it.

    {
      type: 'bulleted-list',
      children: [
        {
          type: 'list-item',
          children: [
            {
              type: 'list-item-child',
              children: [
                {
                  type: 'list-item',
                  children: [
                    {
                      type: 'list-item-child',
                      children: [
                        {
                          text: 'Rodzaj nieruchomości,',
                        },
                      ],
                    },
                  ],
                },
              ],
            },
          ],
        },
      ],
    },

    When the package sees a type list-item, it will render an <li> tag. And when you nest them, it will render an <li> inside an <li>, causing the hydration error you see when you use it with React 18.

    So from what it looks, this is not an issue with the React renderer itself but with how the content is structured on the Rich Text field on the CMS.

    I tried to replicate the structure you provided in the field, but I couldn't do it. When nesting <li>, it always adds a type bulleted-list to its children, avoiding the error you got.

    Check this example:

    CleanShot 2023-02-03 at 14 02 01@2x

    Full content
    import { RichTextContent } from '@graphcms/rich-text-types';
    
    export const content: RichTextContent = {
      children: [
        {
          type: 'bulleted-list',
          children: [
            {
              type: 'list-item',
              children: [
                {
                  type: 'list-item-child',
                  children: [
                    {
                      text: 'Hello 1',
                    },
                  ],
                },
              ],
            },
            {
              type: 'list-item',
              children: [
                {
                  type: 'list-item-child',
                  children: [
                    {
                      text: 'Hello 2',
                    },
                  ],
                },
                {
                  type: 'list-item-child',
                  children: [
                    {
                      type: 'bulleted-list',
                      children: [
                        {
                          type: 'list-item',
                          children: [
                            {
                              type: 'list-item-child',
                              children: [
                                {
                                  text: 'Hello 2.1',
                                },
                              ],
                            },
                          ],
                        },
                      ],
                    },
                  ],
                },
              ],
            },
            {
              type: 'list-item',
              children: [
                {
                  type: 'list-item-child',
                  children: [
                    {
                      text: 'Hello 3',
                    },
                  ],
                },
                {
                  type: 'list-item-child',
                  children: [
                    {
                      type: 'bulleted-list',
                      children: [
                        {
                          type: 'list-item',
                          children: [
                            {
                              type: 'list-item-child',
                              children: [
                                {
                                  text: 'Hello 3.1',
                                },
                              ],
                            },
                            {
                              type: 'list-item-child',
                              children: [
                                {
                                  type: 'bulleted-list',
                                  children: [
                                    {
                                      type: 'list-item',
                                      children: [
                                        {
                                          type: 'list-item-child',
                                          children: [
                                            {
                                              text: 'Hello 3.2',
                                            },
                                          ],
                                        },
                                      ],
                                    },
                                  ],
                                },
                              ],
                            },
                          ],
                        },
                      ],
                    },
                  ],
                },
              ],
            },
            {
              type: 'list-item',
              children: [
                {
                  type: 'list-item-child',
                  children: [
                    {
                      text: 'Hello 4',
                    },
                  ],
                },
              ],
            },
            {
              type: 'list-item',
              children: [
                {
                  type: 'list-item-child',
                  children: [
                    {
                      text: 'Hello 5',
                    },
                  ],
                },
              ],
            },
          ],
        },
        {
          type: 'paragraph',
          children: [
            {
              text: '',
            },
          ],
        },
      ],
    };

    And when rendering the content on a React 18 application, I have no errors on the console and it generates the markup as expected.

    CleanShot 2023-02-03 at 14 05 16@2x

    I hope this clarifies the problem and how the package works in these cases. I'd love to know more about how the content is being added to the Rich Text field at Hygraph. If this list was copied from another place, the issue could be in the Transformer package used by the field.

    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

    2 participants