'Why my nextjs component is rendering twice?
This is a component that render data from firebase storage and make it listed. What the function has to do is set the videos extracted from firebase storage to the useState. That way I can call videos and map into a new component, which happens to be a list of buttons. It works relatively well, the problem is that the component renders twice, the first time it doesn't save the videos in the state, and the second time it does. In other words, the component does not wait for the videos to be saved in the state, and simply renders itself, resulting in the list of buttons with the title of the videos not being displayed.
// ReactJS
import { useState, useEffect } from "react";
// NextJS
import { useRouter } from "next/router";
// Seo
import Seo from "../../../components/Seo";
// Hooks
import { withProtected } from "../../../hook/route";
// Components
import DashboardLayout from "../../../layouts/Dashboard";
// Firebase
import { getDownloadURL, 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([]);
const [videoActive, setVideoActive] = useState(null);
// Routing
const router = useRouter();
const { id } = router.query;
// Reference
const reference = ref(storage, `training/${id}`);
// Check if path is empty
function getVideos() {
let items = [];
listAll(reference).then((res) => {
res.items.forEach(async (item) => {
getDownloadURL(ref(storage, `training/${id}/${item.name}`)).then(
(url) => {
items.push({
name: item.name.replace("-", " "),
href: item.name,
url,
});
}
);
});
});
setVideos(items);
}
useEffect(() => {
getVideos();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [id]);
console.log(videos);
return (
<>
<Seo
title={`${capitalize(id)} Training - Dashboard`}
description={`${capitalize(
id
)} training for all Every Benefits Agents.`}
/>
<DashboardLayout>
<h2>{capitalize(reference.name)}</h2>
<section>
<video controls controlsList="nodownload">
{videoActive && <source src={videoActive} type="video/mp4" />}
</video>
<ul role="list" className="divide-y divide-gray-200 my-4">
{videos.map((video, index) => (
<button key={index} className="py-4 flex">
<div className="w-full 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>
</button>
))}
{console.log("Component rendered")}
</ul>
</section>
</DashboardLayout>
</>
);
}
export default withProtected(Video);
This is an example of how the component is begin rendering:
Anyone has an idea of why this is happening?
Solution 1:[1]
I found the answer in this thread. https://github.com/vercel/next.js/issues/35822
In shortly, This issue is about React 18 Strict Mode. You can read about what's new in the React 18 Strict Mode.
If you are not using strict mode it should not happen. If it is not very important, you can turn off React Strict Mode in the next.config.js. file as shown below.
const nextConfig = {
reactStrictMode: false
}
module.exports = nextConfig
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Ferruh |