Hydration Error in the new Learn Nextjs course
Unanswered
Mrigal carp posted this in #help-forum
Mrigal carpOP
Hi!
Im new to NextJS and I'm currently moving through the next course. I'm currently getting:
Unhandled Runtime Error
Error: Hydration failed because the initial UI does not match what was rendered on the server.
Warning: Did not expect server HTML to contain a <div> in <div>.
See more info here: https://nextjs.org/docs/messages/react-hydration-error
The hydration error is not there if I remove the placeholder entirely from the <input/> inside <Search/>. Any suggestions on how to fix?
Im new to NextJS and I'm currently moving through the next course. I'm currently getting:
Unhandled Runtime Error
Error: Hydration failed because the initial UI does not match what was rendered on the server.
Warning: Did not expect server HTML to contain a <div> in <div>.
See more info here: https://nextjs.org/docs/messages/react-hydration-error
The hydration error is not there if I remove the placeholder entirely from the <input/> inside <Search/>. Any suggestions on how to fix?
2 Replies
Mrigal carpOP
On my Search-component.
Im using it in app/dashboard/invoices/page.tsx like so :
Im using it in app/dashboard/invoices/page.tsx like so :
const Page = ({ searchParams }: Props) => {
const query = searchParams?.query || '';
const currentPage = Number(searchParams?.page) || 1;
const totalPages = fetchInvoicesPages(query);
return (
<div className="w-full">
<div className="flex w-full items-center justify-between">
<h1 className={${lusitana.className} text-2xl}>Invoices</h1>
</div>
<div className="mt-4 flex items-center justify-between gap-2 md:mt-8">
<Search placeholder="Search invoices..."/>
<CreateInvoice />
</div>
<Suspense key={query + currentPage} fallback={<InvoicesTableSkeleton />}>
<Table query={query} currentPage={currentPage} />
</Suspense>
<div className="mt-5 flex w-full justify-center">
{/* <Pagination totalPages={totalPages} /> */}
</div>
</div>
)
};export default function Search({ placeholder }: { placeholder: string }) {
const searchParams = useSearchParams();
const pathname = usePathname();
const { replace } = useRouter();
const handleSearch = useDebouncedCallback((term: string) => {
const params = new URLSearchParams(searchParams)
if (term) {
params.set('query', term);
} else {
params.delete('query');
}
replace(${pathname}?${params.toString()});
}, 300);
return (
<div className="relative flex flex-1 flex-shrink-0">
<label htmlFor="search" className="sr-only">
Search
</label>
<input
id='search'
className="peer block w-full rounded-md border border-gray-200 py-[9px] pl-10 text-sm outline-2 placeholder:text-gray-500"
placeholder={placeholder}
onChange={(e) => {
handleSearch(e.target.value);
}}
defaultValue={searchParams.get('query')?.toString()}
/>
<MagnifyingGlassIcon className="absolute left-3 top-1/2 h-[18px] w-[18px] -translate-y-1/2 text-gray-500 peer-focus:text-gray-900" />
</div>
);
}