Javascript 反应:如何从API响应加载图像?
我的网站太重了,因为它从服务器(谷歌的Firebase Firestore)获取数据后下载了200-400张图片 我提出了两个解决方案,希望有人能回答其中一个:Javascript 反应:如何从API响应加载图像?,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,我的网站太重了,因为它从服务器(谷歌的Firebase Firestore)获取数据后下载了200-400张图片 我提出了两个解决方案,希望有人能回答其中一个: 我想设置每个img都有一个加载状态,让访问者能够看到占位符图像,直到它被加载。在从服务器获取数据之前,我不知道自己获得了多少图像,因此我发现很难通过useState初始化图像加载状态。这可能吗?那怎么办 如何延迟加载图像?图像用占位符初始化。当卷轴靠近图像时,图像开始下载并替换占位符 函数示例(){}{ const[items,se
- 我想设置每个img都有一个加载状态,让访问者能够看到占位符图像,直到它被加载。在从服务器获取数据之前,我不知道自己获得了多少图像,因此我发现很难通过useState初始化图像加载状态。这可能吗?那怎么办
- 如何延迟加载图像?图像用占位符初始化。当卷轴靠近图像时,图像开始下载并替换占位符
函数示例(){}{
const[items,setItems]=useState([])
const[imgLoading,setImgLoading]=useState(true)//imgLoading可能必须是布尔值[]
useffect(()=>{
获取(url)。
.then(response=>setItems(response.data))
}, [])
返回(
items.map(item=>)
)
}
有用于此的库,但如果您想自己使用,可以使用,类似于以下内容:
const{useState,useRef,useffect}=React;
常量LazyImage=(imageProps)=>{
const[shouldLoad,setShouldLoad]=使用状态(false);
常量占位符ref=useRef(null);
useffect(()=>{
如果(!shouldLoad&&placeholderRef.current){
const observer=new IntersectionObserver(([{intersectionRatio}])=>{
如果(相交比率>0){
setShouldLoad(真);
}
});
观察者观察(参考电流);
return()=>observer.disconnect();
}
},[shouldLoad,placeholderRef]);
返回(应加载)
?
,
document.getElementById('app')
);
。滚动列表>*{
边缘顶部:400px;
}
.img占位符{
内容:“占位符!”;
宽度:400px;
高度:300px;
边框:1px纯黑;
背景颜色:银色;
}
将响应数据映射到一个“isLoading”布尔值数组,并更新回调以获取索引并更新特定的“isLoading”布尔值
函数示例(){
const[items,setItems]=useState([]);
const[imgLoading,setImgLoading]=useState([]);
useffect(()=>{
获取(url)。然后((响应)=>{
const{data}=响应;
设置项目(数据);
setImgLoading(data.map(()=>true));
});
}, []);
返回项目。映射((项目,索引)=>(
setImgLoading((加载)=>
正在加载.map((el,i)=>(i==索引?false:el))
)
}
/>
));
}
我将创建一个图像
组件来处理它自己的相关状态。然后在这个组件中,我将使用API来判断图像的容器在用户的浏览器上是否可见
我会有isLoading
和isInview
状态,isLoading
将始终为true
,直到isInview
更新为true
当isLoading
为true
时,我将使用null
作为图像的src
,并显示占位符
当容器在用户浏览器上可见时,仅加载src
现在,我的父组件将执行所有图像URL的请求。它还将有自己的isLoading
状态,当设置true
时,它将显示自己的占位符。当图像url的请求得到解决时,我会在每个url上映射以呈现我的图像组件
export default function App() {
const [imageUrls, setImageUrls] = useState([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
fetchImages().then((response) => {
setImageUrls(response);
setIsLoading((prev) => !prev);
});
}, []);
const images = imageUrls.map((url, index) => <Image key={index} src={url} />);
return <div className="App">{isLoading ? "Please wait..." : images}</div>;
}
导出默认函数App(){
const[imageUrls,setImageUrls]=useState([]);
const[isLoading,setIsLoading]=useState(true);
useffect(()=>{
fetchImages()。然后((响应)=>{
setImageURL(响应);
setIsLoading((prev)=>!prev);
});
}, []);
const images=imageUrls.map((url,索引)=>);
返回{正在加载?“请稍候…”:图像};
}
您可能还希望将某些加载状态与每个图像关联起来,而不是只关联一个整体加载状态,或者这就是您实际要问的问题?我想让imgLoading[]的长度为服务器响应中的数组长度,但在得到服务器响应之前,我不知道长度。第二个问题的答案是,我认为这个库可以获取所有图像URL,并映射它们以显示在图像中?类似于?observer.observe(placeholderRef.current);抛出键入错误,*类型为“null”的参数不能分配给类型为“Element”的参数。ts(2345)*。您知道如何解决它吗?如果您使用的是TypeScript,您将需要执行constplaceholderref=useRef(null)代码>
function Image({ src }) {
const [isLoading, setIsLoading] = useState(true);
const [isInView, setIsInView] = useState(false);
const root = useRef(); // the container
useEffect(() => {
// sets `isInView` to true until root is visible on users browser
const observer = new IntersectionObserver(onIntersection, { threshold: 0 });
observer.observe(root.current);
function onIntersection(entries) {
const { isIntersecting } = entries[0];
if (isIntersecting) { // is in view
observer.disconnect();
}
setIsInView(isIntersecting);
}
}, []);
function onLoad() {
setIsLoading((prev) => !prev);
}
return (
<div
ref={root}
className={`imgWrapper` + (isLoading ? " imgWrapper--isLoading" : "")}
>
<div className="imgLoader" />
<img className="img" src={isInView ? src : null} alt="" onLoad={onLoad} />
</div>
);
}
export default function App() {
const [imageUrls, setImageUrls] = useState([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
fetchImages().then((response) => {
setImageUrls(response);
setIsLoading((prev) => !prev);
});
}, []);
const images = imageUrls.map((url, index) => <Image key={index} src={url} />);
return <div className="App">{isLoading ? "Please wait..." : images}</div>;
}