#Masonry

1 messages · Page 1 of 1 (latest)

mint iron
#

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;
}
woeful crescentBOT
#

Hi @mint iron. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

Based on the knowledge sources provided, I don't have the specific information to guide you on how to use react-responsive-masonry with next/image. However, I can provide some general guidance on how to use next/image.

The next/image component is an extension of the HTML img element, enhanced for performance and user experience. It includes features such as lazy loading and automatic image optimization.

To use next/image, you need to import the Image component from next/image and use it in your component. Here's an example:

import Image from 'next/image'
import mountains from '../public/mountains.jpg'
 
export default function Responsive() {
 return (
 <div style={{ display: 'flex', flexDirection: 'column' }}>
 <Image
 alt="Mountains"
 src={mountains}
 sizes="100vw"
 style={{
 width: '100%',
 height: 'auto',
 }}
 />
 </div>
 )
}

In the above example, the Image component is used to display an image. The src prop is used to specify the image source. The sizes prop is used to specify the sizes of the image. The style prop is used to specify the CSS styles for the image.

If you don't know the aspect ratio, you will need to set the fill prop and set position: relative on the parent. Optionally, you can set object-fit style depending on the desired stretch vs crop behavior:

import Image from 'next/image'
 
export default function Page({ photoUrl }) {
 return (
 <div style={{ position: 'relative', width: '500px', height: '300px' }}>
 <Image
 src={photoUrl}
 alt="Picture of the author"
 sizes="500px"
 fill
 style={{
 objectFit: 'contain',
 }}
 />
 </div>
 )
}

In the above example, the fill prop is used to make the image fill its container. The objectFit style is used to specify how the image should be resized to fit its container.

#

For more detailed information, you can refer to the Next.js documentation (https://nextjs.org/docs/api-reference/next/image).

Please note that the next/image component has some limitations and may not work as expected in some cases. For example, it may not work correctly when used in ESM projects. In such cases, you may need to use workarounds or switch to using the HTML img element.

I hope this helps! If you have any other questions, feel free to ask.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: