Reputation:
I'm encountering an issue with React hydration while using Next.js. I have a Next.js application where I'm rendering a custom pagination and card component. The custom pagination and card component is from "@nextui-org/react"
.
The application runs fine locally, but when deploying it to a production environment and accessing it in the browser, I encounter the following error: "Hydration failed because the initial UI does not match what was rendered on the server." Additionally, there is a warning stating: "Expected server HTML to contain a matching <button>
in <div>
."
import React, { useState } from "react";
import { Pagination as NextUIPagination } from "@nextui-org/react";
import { Card as NextUICard, CardHeader, CardFooter, Image, Button } from "@nextui-org/react";
// Interface for Pagination component props
interface PaginationProps {
total: number;
currentPage: number;
onPageChange: (page: number) => void;
}
// Pagination component
const Pagination: React.FC<PaginationProps> = ({ total, currentPage, onPageChange }) => {
return (
// Render NextUIPagination component with props
<NextUIPagination
key="pagination"
showControls
total={total}
initialPage={currentPage}
onChange={onPageChange}
aria-label="Pagination Navigation"
/>
);
};
// Interface for Card component props
interface CardProps {
location: string;
description: string;
price: string;
rating: string;
image: string;
href: string;
}
// Card component
const Card: React.FC<CardProps> = ({ location, description, price, rating, image, href }) => {
// Initialize state for SVG color
const [svgColor, setSvgColor] = useState<string | undefined>(undefined);
// Function to toggle SVG color change
const toggleSvgColorChange = () => {
// Toggle between 'red' and undefined colors
setSvgColor((prevColor) => (prevColor === 'red' ? undefined : 'red'));
};
// JSX rendering of the Card component
return (
<>
{/* Render NextUICard component with props */}
<NextUICard
key={href}
isPressable
radius="lg"
className="border-none bg-opacity-0 backdrop-blur-lg"
shadow="md"
>
{/* Render Image component with props */}
<Image
isBlurred
isZoomed
alt={description}
src={image}
className="object-cover"
/>
{/* Render CardHeader component */}
<CardHeader className="flex justify-end overflow-hidden py-1 absolute top-2 w-[calc(100%_-_8px)]">
{/* Render Button component with props */}
<Button
isIconOnly
variant="light"
color="default"
size="sm"
className="before:bg-white/10 border-white/20 border-1 before:rounded-xl shadow-small"
onClick={toggleSvgColorChange}
aria-label="Favorite"
>
{/* Heart icon */}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill={svgColor || "currentColor"}
className="w-5 h-5 text-default-500">
<path
d="m9.653 16.915-.005-.003-.019-.01a20.759 20.759 0 0 1-1.162-.682 22.045 22.045 0 0 1-2.582-1.9C4.045 12.733 2 10.352 2 7.5a4.5 4.5 0 0 1 8-2.828A4.5 4.5 0 0 1 18 7.5c0 2.852-2.044 5.233-3.885 6.82a22.049 22.049 0 0 1-3.744 2.582l-.019.01-.005.003h-.002a.739.739 0 0 1-.69.001l-.002-.001Z"/>
</svg>
</Button>
</CardHeader>
{/* Render CardFooter component */}
<CardFooter className="gap-1.5 flex-col items-start">
<div className="w-full flex justify-between">
{/* Render location */}
<p key="location">{location}</p>
<div className="flex flex-row gap-1.5 items-center">
{/* Star icon */}
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
className="w-4 h-4 text-default-400">
<path
fillRule="evenodd"
d="M10.868 2.884c-.321-.772-1.415-.772-1.736 0l-1.83 4.401-4.753.381c-.833.067-1.171 1.107-.536 1.651l3.62 3.102-1.106 4.637c-.194.813.691 1.456 1.405 1.02L10 15.591l4.069 2.485c.713.436 1.598-.207 1.404-1.02l-1.106-4.637 3.62-3.102c.635-.544.297-1.584-.536-1.65l-4.752-.382-1.831-4.401Z"
clipRule="evenodd"/>
</svg>
{/* Render rating */}
<p className="text-default-400 text-sm" key="rating">{rating}</p>
</div>
</div>
{/* Render description */}
<p className="text-sm text-default-500 text-left" key="description">{description}</p>
{/* Render price */}
<p className="text-sm text-default-400" key="price">{price}</p>
</CardFooter>
</NextUICard>
</>
);
};
// Export Pagination and Card components
export { Pagination, Card };
Upvotes: 0
Views: 401
Reputation: 13
I think the problem may be with any one of the Pagination or Card component, more precisely where the 'btn' actually exists. Check if they are actually server side rendered. They might be using some client side properties. Vaguely speaking the html on the server side isn't matching that on the client side, so make sure the next ui components are actually ssr compatible.
Upvotes: 0