我需要动态地知道图像的宽度和高度,所以我使用了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) => v.src === src))
语句,那么image-src就会有重复的值。
你有什么建议吗?
首先将加载部件封装在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>
);
}