【问题标题】:How to re-render a component when all Image objects are loaded in React?在 React 中加载所有 Image 对象时如何重新渲染组件?
【发布时间】:2020-11-12 15:54:59
【问题描述】:

我需要动态知道图像的宽度和高度,所以我使用了Image 对象和onload 事件函数。加载所有图像后,我的组件应该重新渲染并将高度和宽度值传递给子组件(<PhotoGallery />)。

这是我的解决方案。

import React, { useState, useRef } from "react";
import PhotoGallery from "react-photo-gallery";
import Lightbox from "react-image-lightbox";
import { makeStyles, createStyles, Theme, Grid, Button } from "@material-ui/core";
import { PhotoSharp } from "@material-ui/icons";

type Props = {
   photoSrc: string[];
};

type PhotoGalleryImageType = {
   src: string;
   width: number;
   height: number;
};

export default function ProjectGallery(props: Props) {
   const [isLoading, setIsLoading] = useState(true);
   const images = useRef<PhotoGalleryImageType[]>([]);

   props.photoSrcSet.forEach((src) => {
      var photo = new Image();
      photo.src = src;
      photo.onload = () => {
         if (!images.current.some((v) => v.src === src)) {
            images.current.push({ src: src, width: photo.naturalWidth, height: photo.naturalHeight });
         }

         if (images.current.length === props.photoSrcSet.length) {
            setIsLoading(false);
         }
      };
   });

   if (isLoading) {
      return <div>"loading.."</div>;
   }
   return (
      <Grid container justify="center" direction="column">
         <Grid item>
            <PhotoGallery photos={images.current} />
         </Grid>
      </Grid>
   );
}

不过我觉得应该有更好的办法,因为如果没有if (!images.current.some((v) =&gt; v.src === src))声明,图片src就有重复值。

你有什么建议吗?

【问题讨论】:

    标签: javascript reactjs react-hooks


    【解决方案1】:

    首先将加载部分包裹在useEffect() 中,以确保它只触发一次;否则每次更新时都会触发。

    然后,我建议先获取所有唯一来源,然后在循环中使用它来加载和检查。另外,我认为您需要对图像使用 state 而不是 ref:

    import React, { useEffect, useState, useRef } from "react";
    import PhotoGallery from "react-photo-gallery";
    import Lightbox from "react-image-lightbox";
    import { makeStyles, createStyles, Theme, Grid, Button } from "@material-ui/core";
    import { PhotoSharp } from "@material-ui/icons";
    
    type Props = {
       photoSrc: string[];
    };
    
    type PhotoGalleryImageType = {
       src: string;
       width: number;
       height: number;
    };
    
    export default function ProjectGallery(props: Props) {
       const [isLoading, setIsLoading] = useState(true);
       const [images, setImages] = useState<PhotoGalleryImageType[]>([]);
    
       useEffect(() => {
          const sources = [...new Set(props.photoSrcSet)]; // Get unique values
          let loaded = 0; // Initialise a counter
    
          sources.forEach((src) => {
             var photo = new Image();
             photo.src = src;
             photo.onload = () => {
                // Add loaded image to array
                images.push({ src: src, width: photo.naturalWidth, height: photo.naturalHeight });
                // Update the state
                setImages(images);
    
                // Up the loaded counter and compare
                if (++loaded === sources.length) {
                   setIsLoading(false);
                }
             };
          });
       }, []); // Empty dependency array to use it as a componentDidMount
    
       if (isLoading) {
          return <div>"loading.."</div>;
       }
       return (
          <Grid container justify="center" direction="column">
             <Grid item>
                <PhotoGallery photos={images} />
             </Grid>
          </Grid>
       );
    }
    

    【讨论】:

      猜你喜欢
      • 2021-06-07
      • 2020-09-29
      • 1970-01-01
      • 2021-01-02
      • 1970-01-01
      • 1970-01-01
      • 2021-02-15
      • 1970-01-01
      • 2021-06-19
      相关资源
      最近更新 更多