【发布时间】:2022-10-02 05:40:30
【问题描述】:
这是一个渲染来自 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);
这是组件如何开始渲染的示例:
任何人都知道为什么会这样?
-
您是否确保仅在视频中调用重新渲染?也许父组件强制重新渲染。
-
@CubeStorm 有一个父组件,它是仪表板布局。那个也被渲染,但与子组件一起。我注意到这是因为它们都渲染了两次。我将注销功能放在控制台日志中的原因是为了精确检查。由于注销功能仅在布局中呈现。
-
useEffect调用设置状态的getVideos- 状态更改会导致重新渲染。 -
@SeanW 我怀疑是这样的。当我在 listAll 中调用 getDownloadUrl 时会发生这种情况。我假设每次调用每个状态都会重新渲染。问题是我需要两者的信息。 listAll 列出每个视频并将它们显示在列表中,getDownloadUrl 访问firebase url,然后能够在编辑器中呈现视频。有什么办法可以解决吗?
-
我认为 setVideos(items): 被调用了两次,因为您没有等待异步 API 调用。如果您移动 setVideos(items); 会发生什么?在 res.items.forEach 之后立即?那能帮上忙吗?或者您可以尝试等待所有异步 API 调用,然后使用 setVideos(items):。
标签: reactjs next.js firebase-storage use-effect use-state