Javascript 反应:如何从API响应加载图像?

Javascript 反应:如何从API响应加载图像?,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,我的网站太重了,因为它从服务器(谷歌的Firebase Firestore)获取数据后下载了200-400张图片 我提出了两个解决方案,希望有人能回答其中一个: 我想设置每个img都有一个加载状态,让访问者能够看到占位符图像,直到它被加载。在从服务器获取数据之前,我不知道自己获得了多少图像,因此我发现很难通过useState初始化图像加载状态。这可能吗?那怎么办 如何延迟加载图像?图像用占位符初始化。当卷轴靠近图像时,图像开始下载并替换占位符 函数示例(){}{ const[items,se

我的网站太重了,因为它从服务器(谷歌的Firebase Firestore)获取数据后下载了200-400张图片

我提出了两个解决方案,希望有人能回答其中一个:

  • 我想设置每个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>;
}