这是一个组件,从 Firebase 存储中呈现数据并将其列出。该函数的任务是将从 Firebase 存储中提取的视频设置为 useState。这样我就可以调用视频并映射到新的组件中,该组件恰好是一个按钮列表。它表现得相当不错,问题在于该组件会渲染两次,第一次它不会将视频保存在状态中,而第二次则会。换句话说,该组件不等待视频保存在状态中,而只是简单地重新呈现自身,导致未显示带有视频标题的按钮列表。
// 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);
这是组件开始渲染的示例:
有没有人知道为什么会发生这种情况?
useEffect
调用getVideos
来设置状态 - 状态更改会导致重新渲染。 - Sean WuseEffect
中更新了状态。如果你想避免这种情况,可以在服务器端获取视频数据。 - juliomalves