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:
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]);