I want to use react-responsive-masonry with nextjs, it works fine with img tag but when I use Image from next/image, the layout gets fucked up. rewrite following code using next/image (use fill, not a fixed width height) without fucking up the layout.
"use client";
import Masonry, { ResponsiveMasonry } from "react-responsive-masonry";
import { Loading } from "./Loading";
import { useBackendInfinite } from "@/utils/client";
import styles from "@/styles/gallery/page.module.css";
import { redirect } from "next/navigation";
type ImagesResponse = {
items: {
id: string;
image: string;
created_at: string;
}[];
limit: number;
offset: number;
total: number;
};
const Gallery = () => {
const { data, size, setSize, isLoading, error } =
useBackendInfinite<ImagesResponse>(
(page: number, previous: ImagesResponse) => {
if (previous && !previous.items) return null;
return `/gallery?page=${page + 1}`;
}
);
if (error) {
const message =
"Something went wrong while attempting to fetch photos. Please try again later.";
return redirect(`/error?message=${encodeURIComponent(message)}`);
}
const fetchedImages: number =
data?.reduce((acc, curr) => acc + curr.items.length, 0) || 0;
return (
<main>
<h1 className={styles.title}>Photos</h1>
{isLoading ? (
<Loading />
) : (
<div className={styles.gallery}>
<ResponsiveMasonry
columnsCountBreakPoints={{ 200: 1, 750: 2, 1280: 3 }}
>
<Masonry gutter="1rem">
{data?.map((images) =>
images?.items?.map((item: any) => (
<div className={styles.container} key={item.id}>
<img
src={item.image}
alt={item.id}
loading="lazy"
className={styles.image}
/>
</div>
))
)}
</Masonry>
</ResponsiveMasonry>
{data && data[0].total > fetchedImages && (
<button onClick={() => setSize(size + 1)} className={styles.button}>
Load More
</button>
)}
</div>
)}
</main>
);
};
export default Gallery;
.title {
padding-top: 5rem;
padding-bottom: 2rem;
text-align: center;
font-family: var(--font-poppins);
font-size: 4rem;
font-weight: 600;
text-decoration: underline;
text-decoration-thickness: 0.5rem;
text-decoration-color: #4cd964;
text-decoration-skip-ink: none;
}
.gallery {
padding: 0 2.5rem;
}
.container {
overflow: hidden;
border-radius: 20px;
}
.image {
object-fit: cover;
width: 100%;
transition: all 0.2s;
}
.image:hover {
filter: blur(5px);
transform: scale(1.1);
cursor: pointer;
}
.button {
text-align: center;
width: 100%;
margin: 1rem 0;
padding: 1rem 0;
font-family: var(--font-poppins);
font-size: 700;
color: white;
background-color: #4cd964;
border: none;
border-radius: 20px;
}
.button:hover {
opacity: 0.75;
cursor: pointer;
}