reactjs 在react native中分配随机数量的对象

polhcujo  于 2023-05-06  发布在  React
关注(0)|答案(2)|浏览(95)

我从firebase存储中获取视频,现在在应用程序中显示它们。我有3个视频和问题是,每次我渲染屏幕上只有一个视频渲染。UseStatesetVideoUrl分配随机数量的视频URL。有时videoUrls只包含一个视频,而其他时候有2个。我不明白为什么会这样。useEffect也被多次调用。有人能帮忙吗?
这是代码:

import React  from "react";
import firebaseConfig from "../../../firebaseConfig";
import { View, Text, StyleSheet, Dimensions } from "react-native";
import { useEffect, useState } from "react";
import {getStorage, ref, listAll, getDownloadURL } from "firebase/storage"
import { Video } from "expo-av";
// import { WebView } from 'react-native-webview';
import { ActivityIndicator } from "react-native";
// import VideoPlayer from 'react-native-video';


const Program1 = () => {
  const [videoUrls, setVideoUrls] = useState([]);
  // const { width, height } = Dimensions.get("window");
  const [loading, setLoading] = useState(true);
  

   useEffect(() => {
      FetchVideos();
  }, []);

  const FetchVideos = () => {
    const storage = getStorage();
    const listRef = ref(storage, "PersonligUtveckling/videos/");

    listAll(listRef)
      .then((res) => {
        const urls = [];
        res.items.forEach((itemRef) => {
    
          getDownloadURL(itemRef)
          .then((url) => {
            console.log('URL of video file:', url);
            urls.push(url);
            setVideoUrls(urls);
            setLoading(false);
           
          })
        });
      
      })
      .catch((error) => {
        
        console.log(error);
      });
  }

  const handleVideoError = (error) => {
    console.log("Video error:", error);
  };

  const handleVideoLoad = () => {
    console.log("Video loaded");
  };
  

  console.log(videoUrls.length);

  if (loading) {
    return (
      <View style={[styles.container, styles.horizontal]}>
        <ActivityIndicator size="large" />
        { loading && videoUrls.length === 0 ? <Text>No videos found</Text> :  <ActivityIndicator size="large" />}
      </View>
    );
  }

  return (
    <View style={styles.container}>
      <Text>Hello</Text>
    
      {!loading ?
        videoUrls.map((url, index) => (
          <Video
            key={index}
            isMuted={false}
            volume={2.0}
            source={{ uri: url }}
            style={styles.video}
            useNativeControls={true}
            resizeMode="contain"
            onError={handleVideoError}
            onLoad={handleVideoLoad}
          />
        )) : <ActivityIndicator size="large" />}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    paddingTop: 40,
    alignItems: 'center',
  },
  video: {
    width: 320,
    height: 240,
    marginBottom: 20,
  },
});

export default Program1;

控制台日志:

URL of video file: https://firebasestorage.googleapis.com/v0/b/phantoms-mobile-app.appspot.com/o/PersonligUtveckling%2Fvideos%2Fvideo1.mp4?alt=media&token=a4bbedc2-bd17-428d-9bf4-267143af84fc
 LOG  1
 LOG  1
 LOG  URL of video file: https://firebasestorage.googleapis.com/v0/b/phantoms-mobile-app.appspot.com/o/PersonligUtveckling%2Fvideos%2Fvideo.mp4?alt=media&token=d2449d1f-7f03-481f-a1ca-989ba55cd243
 LOG  2
 LOG  URL of video file: https://firebasestorage.googleapis.com/v0/b/phantoms-mobile-app.appspot.com/o/PersonligUtveckling%2Fvideos%2Fvideo2.mp4?alt=media&token=491ec16c-6994-45fb-9b76-40f575fa6df1
 LOG  Video loaded
lsmepo6l

lsmepo6l1#

您没有正确处理此任务的异步特性。您需要等待所有请求都完成,然后才能将它们设置为状态。否则会导致urls阵列出现争用条件。但这个数组不需要存在。你需要把所有的东西都保存在Promise链中。

const FetchVideos = () => {
  const storage = getStorage();
  const listRef = ref(storage, "PersonligUtveckling/videos/");

  listAll(listRef)
    .then((res) =>
      Promise.all(
        res.items.map((itemRef) =>
          getDownloadURL(itemRef).then((url) => {
            console.log("URL of video file:", url);
            return url;
          })
        )
      )
    )
    .then((urls) => setVideoUrls(urls))
    .catch((error) => {
      console.log(error);
    })
    .finally(() => setLoading(false));
};
vmdwslir

vmdwslir2#

问题似乎是由获取视频URL的异步性质引起的。您使用forEach循环遍历这些项,并且对于每个项,您调用异步函数getDownloadURL()。这可能导致setVideoUrls()函数以不可预测的顺序被调用多次。
要修复此问题,可以使用Promise.all()确保在更新状态之前获取所有下载URL。此外,确保在useEffect()中使用依赖数组,以防止多次调用它。

useEffect(() => {
  FetchVideos();
}, []); // Add an empty dependency array to ensure useEffect is called only once.

const FetchVideos = async () => {
  const storage = getStorage();
  const listRef = ref(storage, "PersonligUtveckling/videos/");

  try {
    const res = await listAll(listRef);
    const urlPromises = res.items.map((itemRef) => getDownloadURL(itemRef));
    const urls = await Promise.all(urlPromises);
    console.log('URLs of video files:', urls);
    setVideoUrls(urls);
    setLoading(false);
  } catch (error) {
    console.log(error);
  }
};

相关问题