reactjsnext.jsreact-suspense

React infinite re-renders using nextjs latest


I am using latest Next.js app router version. When I load data in my component it initially renders infinite I don't know why. I have valid data.

SidebarContent.tsx

"use client";
import { useEffect, useState } from "react";
import SlidebarItems from "./SlidebarItems";

export default function SlidebarContent() {
  const [content, setContent] = useState<any>([]);

  useEffect(() => {
    async function getData() {
      const res = await fetch("/api");
      const data = await res.json();
      setContent(data);
    }
    getData();
  }, []);

  const selectItem = (id: string) => {
    const newContent = content.map((item) => {
      if (item.id === id) {
        return { ...item, show: true };
      } else {
        return { ...item, show: false };
      }
    });
    setContent(newContent);
  };
  console.log("renders content");

  return (
    <div className="flex justify-between items-center h-full w-full">
      <div className="sliderRef flex gap-2 items-center h-full w-[85%] overflow-x-hidden">
        hi
        {content &&
          content.map((item) => (
            <SlidebarItems
              key={item.id}
              content={item}
              onClick={(id) => selectItem(id)}
            />
          ))}
      </div>
    </div>
  );
}

SidebarItems.js

"use client";
import Image from "next/image";
const SlidebarItems = async ({ content, onClick }) => {
  return (
    <div
      className={`slidebar-content ${content.show ? "selected" : ""}`}
      onClick={() => onClick(content.id)}
    >
      <div className="flex flex-col items-center w-[98px] ">
        <Image
          src={content.src}
          alt={content.title}
          width={24}
          height={24}
          priority
          className="h-7 w-7 mb-2 "
        />
        <h3 className="text-xs font-medium">{content.title}</h3>
      </div>
    </div>
  );
};

export default SlidebarItems;

When I add React Suspense it works fine but I don't want React Suspense to use because when it re-renders it shows fallback component. I want to use this as normal re-render not infinite.


Solution

  • In your SidebarItems.js you define the functional component as async.

    That makes the function return a promise, which is causing this weird endless re-rendering. Removing the async fixed the issue.


    However in your example, I also got some error regarding loading the images

    Error: Invalid src prop (https://img.icons8.com/ios/50/key.png) on `next/image`, hostname "img.icons8.com" is not configured under images in your `next.config.js`
    

    which you might have to fix as well. Temporarily fixed it with the loader prop to see if the re-rendering issue really was fixed in the example.