#Hydration error about unexpected <button> in <div> , but the component does not have a <button>
22 messages · Page 1 of 1 (latest)
Could you send the page and layout code in your app directory
You can see that the error is from styled-components. Send the code
@modern citrus @novel ice
Okay so I commented out most of the code so that it is the most minimal it can be and still throw the hydration error.
I have CollectionStats.tsx here:
import styled from "styled-components";
import { useContractInfo } from "../api/getContractInfo";
import { useContractAddress } from "../hooks/useContractAddress";
export function CollectionStats() {
const contractAddress = useContractAddress();
const contractInfoQuery = useContractInfo(contractAddress);
if (contractInfoQuery.isLoading || contractInfoQuery.isError) {
return null; // wip: proper error handling
}
return (
<div></div>
)
}
useContractInfo is a custom hook wrapped around react-query useQuery
Is it possible that react-query in this case could be causing issues? It shouldn't though because on the server, it should just returning null because by default isLoading is false yeah?
In terms of page.tsx I have:
import { dehydrate, Hydrate } from "@tanstack/react-query";
import { prefetchBeers } from "@/features/beers";
import { CollectionTokensPageView } from "@/features/collections";
import { getQueryClient } from "@/lib/react-query";
export default async function CollectionTokensPage({
params,
}: {
params: { contractAddress: string };
}) {
const queryClient = getQueryClient();
// add queries here...
await prefetchBeers();
const dehydratedState = dehydrate(queryClient);
return (
<Hydrate state={dehydratedState}>
<CollectionTokensPageView />
</Hydrate>
);
}
CollectionTokensPageView is a client component.
———
In terms of the relevant layout.tsx I have:
import { Metadata } from "next";
import { Suspense } from "react";
import {
CollectionInfoLoadingView,
CollectionPageLayoutView,
} from "@/features/collections";
import { CollectionInfoFetcher } from "@/features/collections";
import { getContractInfo } from "@/features/collections";
/**
* Metadata
*/
interface Props {
params: {
contractAddress: string;
};
}
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { contractAddress } = params;
const contractInfo = await getContractInfo(contractAddress);
return {
title: contractInfo?.name || contractInfo.id,
};
}
/**
* Interfaces
*/
interface CollectionPageLayoutProps {
children: React.ReactNode;
params: {
contractAddress: string;
};
}
/**
* Component
*/
export default async function CollectionPageLayout({
children,
params,
}: CollectionPageLayoutProps) {
return (
<CollectionPageLayoutView
collectionInfoComponent={
<Suspense fallback={<CollectionInfoLoadingView />}>
{/* @ts-expect-error Server Component */}
<CollectionInfoFetcher contractAddress={params.contractAddress} />
</Suspense>
}
>
{children}
</CollectionPageLayoutView>
);
}
Are you using app directory?
Yes I"m using the new app directory
Then, you need to add the “use client” to the top since it should run on client side
CollectionStats.tsx is imported inside of another component I have called CollectionInfo.tsx
And in CollectionInfo.tsx I marked it with "use client" already
So CollectionStats.tsx should be treated as a client component already
Try to remove the code one by one and check which line of code caused the error
Yeah I have been. Unfortunately haven't been able to pin it down. It's super weird cause the error is talking about a <button> but I don't have any in the component it's throwing the error in
Extra hard to pin it down cause I can only reproduce the hydration error 1 out of every like 10-20 times
So have to keep hard refreshing the page until it happens
Okay wait I think it has to do with the react-query related code
This
if (contractInfoQuery.isLoading || contractInfoQuery.isError) {
return null; // wip: proper error handling
}
Strange though, cause on the server and on the client for the first render, contractInfoQuery.isLoading should be true. So first render should match what server rendered.