Home > Software design >  Infinity loop when I try to get information from firebase into nextjs using useEffect
Infinity loop when I try to get information from firebase into nextjs using useEffect

Time:04-12

I am creating a video section for a project with NextJS. I have the videos in firebase storage.

I created a dynamic route, which launch all videos from an specific reference of the bucket. For example, my bucket is somebucket and has a folder called training with categories (category-1, category-2, category-3). Each category will be a dynamic route for example localhost:3000/training/category-1. Up to here, all good.

File for dynamic route [id].js

// ReactJS
import { useState, useEffect } from "react";

// NextJS
import { useRouter } from "next/router";

// Hooks
import { withProtected } from "../../../hook/route";

// Components
import DashboardLayout from "../../../layouts/Dashboard";

// Firebase
import { getMetadata, listAll, ref } from "firebase/storage";
import { storage } from "../../../config/firebase";

// Utils
import capitalize from "../../../utils/capitalize";
import { PlayIcon } from "@heroicons/react/outline";

function Video() {
  // States
  const [videos, setVideos] = useState([]);

  // Routing
  const router = useRouter();
  const { id } = router.query;

  // Reference
  const reference = ref(storage, `training/${id}`);

  useEffect(() => {
    function exec() {
      listAll(reference).then((snapshot) => {
        const videos = [];
        snapshot.items.forEach((video) => {
          videos.push(video);
        });

        setVideos(videos);
      });
    }

    exec();
  }, [reference, videos]);

  return (
    <DashboardLayout>
      <h2>{capitalize(reference.name)}</h2>
      <section>
        <video controls controlsList="nodownload">
          <source
            src="https://example.com"
            type="video/mp4"
          />
        </video>
        <ul role="list" className="divide-y divide-gray-200 my-4">
          {videos.map((video) => (
            <li key={video.name} className="py-4 flex">
              <div className="ml-3 flex flex-row justify-start items-center space-x-3">
                <PlayIcon className="w-6 h-6 text-gray-600" />
                <p className="text-sm font-medium text-gray-900">
                  {video.name}
                </p>
              </div>
            </li>
          ))}
        </ul>
      </section>
    </DashboardLayout>
  );
}

export default withProtected(Video);

I make a dynamic reference based on route with:

// Reference
const reference = ref(storage, `training/${id}`);

This reference will be listed with listAll method as mentioned before:

useEffect(() => {
    function exec() {
      listAll(reference).then((snapshot) => {
        const videos = [];
        snapshot.items.forEach((video) => {
          videos.push(video);
        });

        setVideos(videos);
      });
    }

exec();
}, [reference]);

I push the elements to an state as an array, then the state will be iterated by a component. Apparently work fines, but I got an infinity loop:

enter image description here

Anyone has an idea why this happen?

CodePudding user response:

Im not sure what the issue is but isn't it better to have only the id param in the useEffects array dependency list.

I think this would be better as you only have different videos depending on the route so only when the route changes does the useEffect have to rerun.

CodePudding user response:

Your problem is possibly from this

useEffect(() => {
    function exec() {
      listAll(reference).then((snapshot) => {
        const videos = [];
        snapshot.items.forEach((video) => {
          videos.push(video);
        });

        setVideos(videos); //update `videos` again --> call `useEffect` again due to `videos` update
      });
    }

    exec();
  }, [reference, videos]); //`videos` dependency 

You should remove videos in your useEffect dependency list

useEffect(() => {
    function exec() {
      listAll(reference).then((snapshot) => {
        const videos = [];
        snapshot.items.forEach((video) => {
          videos.push(video);
        });

        setVideos(videos);
      });
    }

    exec();
  }, [reference]);
  • Related