javascript - react : How do you lazyload image from API response?

标签 javascript reactjs react-hooks

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

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

  • 我想将每个 img 设置为具有加载状态,并使访问者能够在加载之前看到占位符图像。因为我不知道从服务器获取数据之前我得到了多少图像,所以我发现很难通过 useState 初始化图像加载状态。这可能吗?那么,如何?
  • 如何延迟加载图片?图像使用占位符进行初始化。当滚动条靠近图像时,图像开始下载并替换占位符。
function sample() {}{
  const [items, setItems] = useState([])
  const [imgLoading, setImgLoading] = useState(true)  // imgLoading might have to be boolean[]
  useEffect(() => {
    axios.get(url).
    .then(response => setItems(response.data))
  }, [])
  return (
    items.map(item => <img src={item.imageUrl} onLoad={setImgLoading(false)} />)
  )
}

最佳答案

我会创建一个 Image 组件来处理它自己的相关状态。然后在这个组件中,我会使用 IntersectionObserver用于判断图像容器在用户浏览器上是否可见的 API。

我会有 isLoadingisInview 状态,isLoading 将始终为 true 直到 isInview 更新为 true

虽然 isLoadingtrue,但我会使用 null 作为图像的 src 并将显示占位符。

当容器在用户浏览器上可见时,仅加载 src

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>
  );
}

我还会有 CSS 样式来切换占位符和图像的 display 属性。

.App {
  --image-height: 150px;
  --image-width: var(--image-height);
}

.imgWrapper {
  margin-bottom: 10px;
}

.img {
  height: var(--image-height);
  width: var(--image-width);
}

.imgLoader {
  height: 150px;
  width: 150px;
  background-color: red;
}

/* container is loading, hide the img */
.imgWrapper--isLoading .img {
  display: none;
}

/* container not loading, display img */
.imgWrapper:not(.imgWrapper--isLoading) .img {
  display: block;
}

/* container not loading, hide placeholder */
.imgWrapper:not(.imgWrapper--isLoading) .imgLoader {
  display: none;
}

现在我的父组件将执行对所有图像 url 的请求。它还会有自己的 isLoading 状态,当设置为 true 时,它会显示自己的占位符。当图像 url 的请求得到解决时,我将映射到每个 url 以呈现我的 Image 组件。

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>;
}

Edit flamboyant-kare-zz6qq

关于javascript - react : How do you lazyload image from API response?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63405009/

相关文章:

javascript - 如何以 Angular 2 - 4 递增变量

javascript - 创建二维 View

javascript - AWS Amplify 登录 `currentAuthenticatedUser` 在登录后返回 `User is not authenticated`

node.js - 浏览器控制台错误: Cannot find module 'react-dom/lib/ReactPerf' from 'react/lib/ReactAddonsDOMDependencies.js'

javascript - 在 createElement() 上 react 生命周期方法

javascript - 如何以动态形式创建和存储多个输入的值?

javascript - 将新键/值对添加到 chrome.storage.sync 中的现有键

reactjs - 如何通过 React Hook 使用 throttle 或去抖?

Javascript 未在 Internet Explorer 中实现错误