简体   繁体   English

如何防止set state before useEffect?

[英]How to prevent set state before useEffect?

I have a React/Next component.我有一个 React/Next 组件。 This component download data from firebase storage based on a route.该组件根据路由从 firebase 存储中下载数据。 For example, for route http://localhost:3000/training/javascript the component with get data from /training/javascript router in firebase storage.例如,对于路由 http://localhost:3000/training/javascript,组件从 firebase 存储中的 /training/javascript 路由器获取数据。

// 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 prettysize from "prettysize";
import capitalize from "../../../utils/capitalize";
import { PlayIcon } from "@heroicons/react/outline";
import { async } from "@firebase/util";

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

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

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

  useEffect(() => {
    const fetchData = async () => {
      let tempVideos = [];
      let completeVideos = [];
      const videos = await listAll(reference);

      videos.items.forEach((video) => {
        tempVideos.push(video);
      });

      tempVideos.forEach((video) => {
        getMetadata(ref(storage, video.fullPath)).then((metadata) => {
          completeVideos.push({
            name: metadata.name,
            size: prettysize(metadata.size),
          });
        });
      });

      tempVideos.forEach((video) => {
        getDownloadURL(ref(storage, video.fullPath)).then((url) => {
          completeVideos.forEach((completeVideo) => {
            if (completeVideo.name === video.name) {
              completeVideo.url = url;
            }
          });
        });
      });

      setVideos(completeVideos);
    };

    fetchData();
  }, [id]);

  console.log("Render", videos)
  return (
    <>
      <Seo
        title={`${capitalize(id)} Training - Dashboard`}
        description={`${capitalize(
          id
        )} training for all Every Benefits Agents.`}
      />
      <DashboardLayout>
        <h2>{capitalize(reference.name)}</h2>
        <ul>
          {videos.map((video) => {
            return (
              <li key={video.name}>
                <a href={video.url} target="_blank" rel="noopener noreferrer">
                  <PlayIcon />
                  {video.name}
                </a>
                <span>{video.size}</span>
              </li>
            );
          })}
        </ul>
      </DashboardLayout>
    </>
  );
}

export default withProtected(Video);

I have an useState that should be the array of videos from firebase. I use an useEffect to get the data from firebase and extract the needed information.我有一个 useState,它应该是来自 firebase 的视频数组。我使用 useEffect 从 firebase 获取数据并提取所需的信息。 Some medatada and the url.一些 medatada 和 url。

Everything's fine.一切安好。 The information is extracted, and is updated to the state correctly.信息被提取,并正确更新到 state。 But when the state is updated, it's no showings on the screen.但是当state更新时,屏幕上没有任何显示。

This is a console.log of the videos state updated, so you can see it's correctly updated.这是视频 state 更新的控制台日志,因此您可以看到它已正确更新。 在此处输入图像描述

You messed up a bit with asynchronous code and loops, this should work for you:你搞砸了异步代码和循环,这应该适合你:

 useEffect(() => { const fetchData = async () => { try { const videos = await listAll(reference); const completeVideos = await Promise.all( videos.items.map(async (video) => { const metadata = await getMetadata(ref(storage, video.fullPath)); const url = await getDownloadURL(ref(storage, video.fullPath)); return { name: metadata.name, size: prettysize(metadata.size), url, }; }) ); setVideos(completeVideos); } catch (e) { console.log(e); } }; fetchData(); }, []);

Promise.all takes an array of promises, and returns a promise that resolves with an array of all the resolved values once all the promises are in the fulfilled state. This is useful when you want to perform asynchronous operations like your getMetaData and getDownloadURL, on multiple elements of an array. Promise.all接受一组承诺,并返回一个 promise,一旦所有承诺都已fulfilled ,它就会使用所有已解析值的数组进行解析 state。当您要执行异步操作(如 getMetaData 和 getDownloadURL)时,这很有用数组的多个元素。 You will use .map instead of .forEach since map returns an array, while forEach does not.您将使用.map而不是.forEach ,因为 map 返回一个数组,而 forEach 不返回。 By passing an async function to .map , since an async function always returns a Promise , you are basically creating an array of promises.通过将async function 传递给.map ,因为async function 总是返回Promise ,您基本上是在创建一个承诺数组。 and that's what you can feed Promise.all with.这就是你可以用来喂养Promise.all的东西。 That's it, now it just waits that all the async calls are done and you can just await for Promise.all to resolve.就是这样,现在它只是等待所有异步调用完成,您可以await Promise.all来解决。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 由于在设置 state 之前进行组件渲染,我的 React 组件失败了。 我该如何解决这个问题? - My react component is failing due to component rendering before state is set. How can I resolve this issue? 反应 useEffect 未正确更新 State - React useEffect Not Updating State Properly 如何确保 function 1 在 function 2 开始之前在 useEffect 挂钩中结束? - How can I make sure that function 1 ends before function 2 starts within useeffect hook? 即使 state 数据没有改变,使用效果无限循环 - useeffect infinite loop even though state data is not changing 在我加载 state 时设置超时以防止登录页面在用户完成身份验证之前闪烁是不好的做法吗? - Is it bad practice to have a setTimeout on my loading state to prevent the log in page from flashing before the user is finished being authenticated? UseEffect 依赖数组保持运行即使 state 没有改变 - UseEffect dependency array keeps running even state does not change 如何根据 FirebaseAuth State 设置导航到特定页面? - How to set up navigation to a specific page base on FirebaseAuth State? 如何在 React useEffect 和 firebase 中正确渲染组件 - How To render properly a component in react useEffect and firebase useEffect 中的数据究竟如何影响页面加载 - How exactly data in useEffect work on page load 无法对未安装的组件执行 React state 更新。(UseEffect)(Context API)(REACT.js) - Can't perform a React state update on an unmounted component.(UseEffect)(Context API)(REACT.js)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM