如何在React.js中预加载图像? 我有下拉选择组件,其功能类似菜单,但我必须预先加载项目的图像图标,因为有时它们在首次打开时不可见。
我试过了:
https://github.com/sambernard/react-preload
https://github.com/wizardzloy/react-img-preload
第一个有很好的API易于理解和使用,但是是spaming控制台,警告图像没有加载,即使它们是。 第二个有奇怪的API,但我尝试了例子,它没有预加载任何东西。
所以我可能需要自己实现一些东西,但不知道从哪里开始。或者另一种可能性是用webpack加载它们。
答案 0 :(得分:18)
假设您有pictures: string[];
- 在您的组件的道具中定义的图片网址数组。
您应该在组件中定义componentDidMount()方法,然后为要预加载的每个图片创建新的Image对象:
componentDidMount() {
this.props.pictures.forEach((picture) => {
const img = new Image();
img.src = picture.fileName;
});
}
它强制浏览器加载所有图像。 此示例使用TypeScript编写。
答案 1 :(得分:3)
如果某些图像在缓存后仍在重新加载,请尝试将它们存储在window
对象中:
componentDidMount() {
const imagesPreload = [image1, image2, image3];
imagesPreload.forEach((image) => {
const newImage = new Image();
newImage.src = image;
window[image] = newImage;
});
}
(您无需从window
对象调用图像)
答案 2 :(得分:2)
如果只提供一些小的“图标” - (为什么不使用字体?) - 如果服务器提供gzip文件,你可以使用base64。
否则,如果select不能立即显示,您还可以将img标签(带display: none
)添加到之前的HTML中。另一种方法是将Image对象附加到DOM并在显示组件之前等待.onload
(这种方法由您提到的库使用)。
据我所知,webpack或者反应不能为你做任何特别的事。这是客户端的一些东西,这些只是实现自己的预加载API的工具(甚至使用JS / TS,React,Angular中的现有API ......)
答案 3 :(得分:2)
重要的是将图像变量保存为PERSISTANT。
在持久性上下文中,在全局变量中或在显示图像之前不会卸载的组件中:
window.preloadedPictures = []
在我的组件中:
var preloadedData = pictures.map((picture) => {
const img = new Image();
img.src = picture.fileName;
return img
});
myContextOrGlobalVar.preloadedPictures = preloadedData ///IMPORTANT
答案 4 :(得分:0)
这有效:
import im1 from 'img/im1.png'
import im2 from 'img/im2.png'
import im3 from 'img/im3.png'
componentDidMount() {
imageList = [im1, im2, im3]
imageList.forEach((image) => {
new Image().src = image
});
}
答案 5 :(得分:0)
我的朋友,您可以选择链接rel预加载/ prefetch和webpack延迟加载块。
更多信息:
答案 6 :(得分:0)
假设您有一个images
数组,其中包含每个图像的数据,则可以一次性完成
componentDidMount() {
this.props.images.forEach(image => (new Image().src = image.src));
}
答案 7 :(得分:0)
反应钩子方式
useEffect(() => {
//preloading image
faceArray.forEach((face) => {
const img = new Image();
img.src = image;
});
}, []);
答案 8 :(得分:0)
这里有一种方法可以将此功能放入自定义挂钩中,您可以在任何功能组件中使用该挂钩。
一些答案遗漏的一个重要部分是在诸如 window 对象之类的东西中存储对预加载图像的引用。如果您不这样做,您可能会发现浏览器会在实际需要图像时重新请求它们,尽管它们已经被预加载。
第一次使用此钩子时,会在 window
中添加一个名为 usePreloadImagesData
的键,并将其初始化为 {}
。
每次在组件中使用钩子时,都会向 window.usePreloadImagesData
添加一个新键。密钥的名称是随机生成的。它被初始化为 []
。
钩子采用图像源字符串数组。对于每个图像源,都会创建一个 new Image()
并将其添加到 window.usePreloadImagesData[randomStr]
数组中。
当组件被卸载,或者传递给自定义钩子的数组发生变化时,window.usePreloadImagesData[randomStr]
会被删除以避免内存泄漏。
这个例子是用 Typescript 编写的。
import { useEffect } from 'react';
declare global {
interface Window {
usePreloadImagesData?: Record<string, unknown[]>;
}
}
export const usePreloadImages = (imageSrcs: string[]): void => {
useEffect(() => {
const randomStr = Math.random().toString(32).slice(2) + Date.now();
window.usePreloadImagesData = window.usePreloadImagesData ?? {};
window.usePreloadImagesData[randomStr] = [];
for (const src of imageSrcs) {
// preload the image
const img = new Image();
img.src = src;
// keep a reference to the image
window.usePreloadImagesData[randomStr].push(img);
}
return () => {
delete window.usePreloadImagesData?.[randomStr];
};
}, [ imageSrcs ]);
};
使用此钩子时,确保传递给钩子的图像源字符串数组是常量;否则会导致不必要的重新渲染。即,要么在组件外创建它,要么使用 React.useMemo
之类的东西。
例如
import React from 'react';
import { usePreloadImages } from '../hooks/usePreloadImages';
import img1 from './image-1.jpg';
import img2 from './image-2.jpg';
const preload = [ img1, img2 ]; // create constant array here, outside the component
export const MyComponent: React.FC = () => {
usePreloadImages(preload); // correct
// usePreloadImages([ img1, img2 ]); // incorrect
return (
// ...
);
};
答案 9 :(得分:-3)
我认为最好的方法是对图像使用数据URI
componentWillMount() {
this.setState({image: "data:image/gif;base64,R0lGODlhEAAQAMQA..."})
}
render() {
<img src={this.state.image} />
}