TanStack / table

🤖 Headless UI for building powerful tables & datagrids for TS/JS - React-Table, Vue-Table, Solid-Table, Svelte-Table
https://tanstack.com/table
MIT License
25.09k stars 3.07k forks source link

Hydration Error: "An error occurred during hydration. The server HTML was replaced with client content in <astro-island>" (Astro Website) #936 #4973

Closed lucaswalter closed 1 year ago

lucaswalter commented 1 year ago

Describe the bug

Hello, I'm having a bit of trouble tracing down the root of this so forgive me if this is not the correct spot to note this but I wanted to raise an issue to see if anyone else has encountered this or has a path forward.

I am using shadcn inside an Astro project and am attempting to display data in a DataTable component as documented on the shadcn documentation site. When I attempt to run the website locally, I get this hydration error when trying to apply custom formatting or JSX to the header or cell items on my ColumnDef. An error occurred during hydration. The server HTML was replaced with client content in 'astro-island'

I've been able to reproduce this exact same issue on a fresh repro project after following these exact steps:

Here is the repro link which uses exact same component as in the docs: https://github.com/lucaswalter/astro-shadcn-tanstack-repro/blob/main/src/pages/index.astro

In short, I am attempting to render and hydrate the DataTable like in the snippet below. Is it currently possible to use the DataTable component in an Astro project?

<Layout title="Welcome to Astro.">
    <main>
        <h1 class="mb-2">
            Welcome to <span class="text-gradient">Astro</span>
        </h1>

                 <!-- Data Table Usage -->
        <DataTable client:load columns={columns} data={data} />
    </main>
</Layout>

Full Strack Trace

react-dom.development.js:86 Warning: Did not expect server HTML to contain a <div> in <th>.
    at th
    at http://localhost:3000/src/components/ui/table.tsx:53:3
    at tr
    at http://localhost:3000/src/components/ui/table.tsx:44:3
    at thead
    at http://localhost:3000/src/components/ui/table.tsx:17:3
    at table
    at div
    at http://localhost:3000/src/components/ui/table.tsx:5:3
    at div
    at DataTable (http://localhost:3000/src/components/data-table.tsx:6:3)
printWarning @ react-dom.development.js:86
error @ react-dom.development.js:60
warnForDeletedHydratableElement @ react-dom.development.js:10477
didNotHydrateInstance @ react-dom.development.js:11424
warnUnhydratedInstance @ react-dom.development.js:12313
warnIfUnhydratedTailNodes @ react-dom.development.js:12707
popHydrationState @ react-dom.development.js:12677
completeWork @ react-dom.development.js:22176
completeUnitOfWork @ react-dom.development.js:26593
performUnitOfWork @ react-dom.development.js:26568
workLoopConcurrent @ react-dom.development.js:26543
renderRootConcurrent @ react-dom.development.js:26505
performConcurrentWorkOnRoot @ react-dom.development.js:25738
workLoop @ scheduler.development.js:266
flushWork @ scheduler.development.js:239
performWorkUntilDeadline @ scheduler.development.js:533
react-dom.development.js:86 Warning: An error occurred during hydration. The server HTML was replaced with client content in <astro-island>.
printWarning @ react-dom.development.js:86
error @ react-dom.development.js:60
errorHydratingContainer @ react-dom.development.js:11473
recoverFromConcurrentError @ react-dom.development.js:25846
performConcurrentWorkOnRoot @ react-dom.development.js:25750
workLoop @ scheduler.development.js:266
flushWork @ scheduler.development.js:239
performWorkUntilDeadline @ scheduler.development.js:533
react-dom.development.js:12507 Uncaught Error: Hydration failed because the initial UI does not match what was rendered on the server.
    at throwOnHydrationMismatch (react-dom.development.js:12507:9)
    at popHydrationState (react-dom.development.js:12678:9)
    at completeWork (react-dom.development.js:22176:30)
    at completeUnitOfWork (react-dom.development.js:26593:16)
    at performUnitOfWork (react-dom.development.js:26568:5)
    at workLoopConcurrent (react-dom.development.js:26543:5)
    at renderRootConcurrent (react-dom.development.js:26505:7)
    at performConcurrentWorkOnRoot (react-dom.development.js:25738:38)
    at workLoop (scheduler.development.js:266:34)
    at flushWork (scheduler.development.js:239:14)
throwOnHydrationMismatch @ react-dom.development.js:12507
popHydrationState @ react-dom.development.js:12678
completeWork @ react-dom.development.js:22176
completeUnitOfWork @ react-dom.development.js:26593
performUnitOfWork @ react-dom.development.js:26568
workLoopConcurrent @ react-dom.development.js:26543
renderRootConcurrent @ react-dom.development.js:26505
performConcurrentWorkOnRoot @ react-dom.development.js:25738
workLoop @ scheduler.development.js:266
flushWork @ scheduler.development.js:239
performWorkUntilDeadline @ scheduler.development.js:533
react-dom.development.js:12507 Uncaught Error: Hydration failed because the initial UI does not match what was rendered on the server.
    at throwOnHydrationMismatch (react-dom.development.js:12507:9)
    at tryToClaimNextHydratableInstance (react-dom.development.js:12535:7)
    at updateHostComponent (react-dom.development.js:19902:5)
    at beginWork (react-dom.development.js:21618:14)
    at beginWork$1 (react-dom.development.js:27426:14)
    at performUnitOfWork (react-dom.development.js:26560:12)
    at workLoopConcurrent (react-dom.development.js:26543:5)
    at renderRootConcurrent (react-dom.development.js:26505:7)
    at performConcurrentWorkOnRoot (react-dom.development.js:25738:38)
    at workLoop (scheduler.development.js:266:34)
throwOnHydrationMismatch @ react-dom.development.js:12507
tryToClaimNextHydratableInstance @ react-dom.development.js:12535
updateHostComponent @ react-dom.development.js:19902
beginWork @ react-dom.development.js:21618
beginWork$1 @ react-dom.development.js:27426
performUnitOfWork @ react-dom.development.js:26560
workLoopConcurrent @ react-dom.development.js:26543
renderRootConcurrent @ react-dom.development.js:26505
performConcurrentWorkOnRoot @ react-dom.development.js:25738
workLoop @ scheduler.development.js:266
flushWork @ scheduler.development.js:239
performWorkUntilDeadline @ scheduler.development.js:533
react-dom.development.js:19849 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.
    at updateHostRoot (react-dom.development.js:19849:57)
    at beginWork (react-dom.development.js:21615:14)
    at beginWork$1 (react-dom.development.js:27426:14)
    at performUnitOfWork (react-dom.development.js:26560:12)
    at workLoopSync (react-dom.development.js:26466:5)
    at renderRootSync (react-dom.development.js:26434:7)
    at recoverFromConcurrentError (react-dom.development.js:25850:20)
    at performConcurrentWorkOnRoot (react-dom.development.js:25750:22)
    at workLoop (scheduler.development.js:266:34)
    at flushWork (scheduler.development.js:239:14)
updateHostRoot @ react-dom.development.js:19849
beginWork @ react-dom.development.js:21615
beginWork$1 @ react-dom.development.js:27426
performUnitOfWork @ react-dom.development.js:26560
workLoopSync @ react-dom.development.js:26466
renderRootSync @ react-dom.development.js:26434
recoverFromConcurrentError @ react-dom.development.js:25850
performConcurrentWorkOnRoot @ react-dom.development.js:25750
workLoop @ scheduler.development.js:266
flushWork @ scheduler.development.js:239
performWorkUntilDeadline @ scheduler.development.js:533

Your minimal, reproducible example

https://stackblitz.com/github/lucaswalter/astro-shadcn-tanstack-repro

Steps to reproduce

See the repro project here: https://github.com/lucaswalter/astro-shadcn-tanstack-repro/blob/main/src/pages/index.astro#L41 or StackBlitz

  1. Clone repro project
  2. Install dependencies
  3. Run npm run dev
  4. Open in browser and see error in console

Expected behavior

As a user, I expect to be able to provide custom cell and header JSX which will render and hydrate on my website.

How often does this bug happen?

Every time

Screenshots or Videos

image

Platform

react-table version

^8.9.3

TypeScript version

No response

Additional context

No response

Terms & Code of Conduct

lucaswalter commented 1 year ago

To clarify further, this seems to only happen when I utilize "Cell Formatting" on the table like in this snippet:

export const columns: ColumnDef<Payment>[] = [
  {
    accessorKey: 'status',
    header: 'Status',
  },
  {
    accessorKey: 'email',
    header: 'Email',
  },
  {
    accessorKey: 'amount',
    // header: 'Amount', // This works for me
    header: () => <div className="text-right">Amount</div>, // This does not work for me
  },
];
Rohan-07 commented 1 year ago

Hi, I tried to reproduce this issue. According to my findings the react 18 version is creating the issue. Try to use react 17 version and it will fix most of the hydration errors.

In React 18 here are some of the breaking changes that might be responsible for this.

lucaswalter commented 1 year ago

Thanks @Rohan-07 for the additional context and for sharing your findings. It will be difficult for me to downgrade to react 17 because of other peer dependencies I have in my project.

From what you found, was the React.render and ReactDOM.hydrate usage actually in the @tanstack/react-table dependency? Or was it used somewhere else?

I personally think it may be best to go forward raising an issue in the appropriate spot so it can be fixed on the latest dependency versions. Would you mind sharing a bit more context around that? I'd be happy to take forward with reporting the issue.

lucaswalter commented 1 year ago

Workaround documented here: https://discord.com/channels/830184174198718474/1130952479555735612

kyeshmz commented 11 months ago

@lucaswalter can you share your findings? This link is broken and I am in the same boat as you.

jacobgranberry commented 10 months ago

@lucaswalter can you share your findings? This link is broken and I am in the same boat as you.

Heres the link it referenced. Discord links are bad because you cant really index the discord stuff. So I'm going to copy/paste the reference here for future reference:


here another solution
on the unmodified example from lucaswalter repo just change this 
<DataTable client:load columns={columns} data={data} />

to this, (removing the client directive)
<DataTable columns={columns} data={data} />

this shows a sort of mismatch between react usage as a component rendered by Astro on server side and the workaround usage as client component when wrapped in another jsx.
When removing the client:load directive, there's obviously no react on client anymore and it's all rendered to html by astro on serevr side```
khanakia commented 5 months ago

Any idea how to fix this hydration error ?

khanakia commented 3 months ago

@tannerlinsley This bug made the react table useless as it can't be used in Astro.js anyway

KevinVandy commented 3 months ago

This seems more like an astro/react bug than a TanStack Table bug. I don't know how we would package this differently that would make a difference.

khanakia commented 3 months ago

PS: The Astro author says vice versa like this is a library bug and I can confirm it is a react-table bug because In the past I did debug the issue and the react table was adding an unnecessary div inside the tag which creates the problem.

More detail here: https://github.com/withastro/astro/issues/10860

KevinVandy commented 3 months ago

Do you think that the problem is that your column definitions are not defined inside of a react component? Anything with jsx like a custom cell render should probably only be defined inside of react, and not in an Astro file.

khanakia commented 3 months ago

Actually, it could be a related bug too if I create the react table as separate component then import into astro page then it works fine without hydration error.

Hydration Error

page.astro

---
import Layout from '../layouts/Layout.astro'
import { DataTable } from '@/components/datatable/datatable'
import { createColumnHelper } from '@tanstack/react-table'

const columnHelper = createColumnHelper()

const columns = [
  columnHelper.accessor('name', {
    cell: (info) => info.getValue(),
  }),
]

const defaultData = [
  {
    name: 'tanner',
    lastName: 'linsley',
    age: 24,
    visits: 100,
    status: 'In Relationship',
    progress: 50,
  },
]
---

<Layout title='List of Countries in the World'>
  <DataTable data={defaultData} columns={columns} client:load />
</Layout>
chunk-BVI7NZOO.js?v=4b8af205:521 Warning: Did not expect server HTML to contain the text node "tanner" in <td>.
    at td
    at _c13 (http://localhost:4321/src/components/ui/table.tsx:142:13)
    at tr
    at _c9 (http://localhost:4321/src/components/ui/table.tsx:96:12)
    at tbody
    at _c5 (http://localhost:4321/src/components/ui/table.tsx:53:12)
    at table
    at div
    at _c (http://localhost:4321/src/components/ui/table.tsx:20:11)
    at div

Working Good

Separate React Component TestTable.tsx

import { createColumnHelper } from '@tanstack/react-table'
import { DataTable } from '@/components/datatable/datatable'

const columnHelper = createColumnHelper()

const columns = [
  columnHelper.accessor('name', {
    cell: (info) => info.getValue(),
  }),
]

const defaultData = [
  {
    name: 'tanner',
    lastName: 'linsley',
    age: 24,
    visits: 100,
    status: 'In Relationship',
    progress: 50,
  },
]

export const Demo1 = () => {
  return <DataTable data={defaultData} columns={columns} />
}

page.astro

---
import Layout from '../layouts/Layout.astro'
import { Demo1 } from '@/components/rt/Demo1'
---

<Layout title='List of Countries in the World'>
    <Demo1 />
</Layout>