I am displaying a series of images hosted in CDN on my NextJS page in the “masonry layout” structure (Just like Pinterest). As shown in .
When I try to load it on my desktop it’s working fine. But only when I load it on my iPhone or lower screen sizes, the screen
or it displays “A problem repeatedly occurred”() Can you please tell me how to fix it or debug it.
The code is as below for this page. All of this happens inside a [slug] folder for multi page rendering.
'use client'
import React, { useEffect, useState } from 'react'
import Image from 'next/image'
import { useParams, useRouter } from 'next/navigation'
import { IoDownloadOutline } from "react-icons/io5";
import { useInView } from 'react-intersection-observer';
import LoadingSpinner from '../../components/LoadingSpinner'
import { RiGeminiFill } from "react-icons/ri";
interface Wallpaper {
id: string | number
thumbnail_url: string
downloads: number
categories: Array<string>
resolution_count: number
}
function CategoryPage() {
const [wallpapers, setWallpapers] = useState<Wallpaper[]>([])
const [page, setPage] = useState(1)
const [hasMore, setHasMore] = useState(true)
const { ref, inView } = useInView()
const params = useParams()
const router = useRouter()
const [initialLoading, setInitialLoading] = useState(true)
useEffect(() => {
const fetchWallpapers = async () => {
try {
const response = await fetch(`${process.env.BACKEND_PUBLIC_API_URL}/fetch_wallpapers/category/${params.category}?page=${page}`)
const data = await response.json()
if (data.length === 0) {
setHasMore(false)
return
}
setWallpapers(prev => {
const existingIds = new Set(prev.map((w: Wallpaper) => w.id))
const newWallpapers = data.filter((w: Wallpaper) => !existingIds.has(w.id))
return [...prev, ...newWallpapers]
})
} catch (error) {
console.error('Error fetching wallpapers:', error)
} finally {
setInitialLoading(false)
setIsLoading(false)
}
}
if (hasMore) {
fetchWallpapers()
}
}, [params.category, page, hasMore])
const [isLoading, setIsLoading] = useState(false)
useEffect(() => {
if (inView && hasMore && !isLoading) {
setIsLoading(true)
setPage(prev => prev + 1)
}
}, [inView, hasMore, isLoading])
useEffect(() => {
setWallpapers([])
setPage(1)
setHasMore(true)
setIsLoading(false)
}, [params.category])
const handleWallpaperClick = (wallpaper: Wallpaper) => {
router.push(`/wallzone/wallpaper_view/${wallpaper.id}?categories=${wallpaper.categories.join(',')}`)
}
return (
<div className="p-4 bg-paper-white min-h-screen pt-20
max-sm:p-1 max-sm:pt-20">
{initialLoading ? (
<div className="h-[calc(100vh-80px)] flex items-center">
<LoadingSpinner />
</div>
) : (
<div className="gap-3
max-sm:columns-2 max-sm:gap-1
md:columns-3
lg:columns-5
2xl:columns-6 2xl:gap-4 [column-fill:_balance]">
{wallpapers.map((wallpaper) => (
<div key={wallpaper.id} className="break-inside-avoid mb-4" onContextMenu={(e) => e.preventDefault()}>
<div
className="relative w-full overflow-hidden rounded-lg group cursor-pointer"
onClick={() => handleWallpaperClick(wallpaper)}
>
{wallpaper.thumbnail_url && (<Image
src={wallpaper.thumbnail_url}
alt={wallpaper.id.toString()}
width={0}
height={0}
loading="lazy"
className="w-full h-auto lg:hover:scale-105 lg:transition-transform lg:duration-300"
sizes="(max-width: 640px) 90vw,
(max-width: 768px) 45vw,
(max-width: 1024px) 30vw,
22vw"
style={{
width: '100%',
height: 'auto',
minHeight: '100px',
}}
unoptimized
/>)}
{wallpaper.resolution_count === 4 && (
<div className="absolute top-2 right-2">
<RiGeminiFill className="text-yellow-400 text-xl" />
</div>
)}
<button className="absolute flex items-center rounded-full px-2 shadow-md text-white opacity-0 group-hover:opacity-100 transition-opacity duration-300
max-lg:bottom-2 max-lg:right-2
lg:bottom-1 lg:right-1">
<IoDownloadOutline className="mr-1" />
{wallpaper.downloads}
</button>
</div>
</div>
))}
</div>
)}
{isLoading && !initialLoading && (
<div className="py-4">
<LoadingSpinner />
</div>
)}
</div>
)
}
export default CategoryPage