简体   繁体   English

"如何在 React 中缓存图像?"

[英]How To Cache Images in React?

Suppose I have a list of url's like so :假设我有一个这样的 url 列表:

[ '/images/1', '/images/2', ... ]

And I want to prefetch n of those so that transitioning between images is faster.我想预取其中的n ,以便图像之间的转换更快。 What I am doing now in componentWillMount is the following:我现在在componentWillMount中所做的事情如下:

componentWillMount() {
      const { props } = this;
      const { prefetchLimit = 1, document = dummyDocument, imgNodes } = props;
      const { images } = document;
      const toPrefecth = take(prefetchLimit, images);
      const merged = zip(toPrefecth, imgNodes);

      merged.forEach(([url, node]) => {
        node.src = url;
      });
    }

with imgNodes being defined like so: imgNodes的定义如下:

imgNodes: times(_ => new window.Image(), props.prefetchLimit),

and times , zip , and take coming from ramda .timesziptake来自ramda

Now when I use those urls inside of react like so:现在,当我在反应中使用这些网址时,如下所示:

<img src={url} />

it hits the browser cache according to the Etag and Expire tags regardless of where the url is used.无论在哪里使用 URL,它都会根据EtagExpire标签访问浏览器缓存。 I also plan on using this to prefetch the next n images whenever we hit n - 1 inside of the view, reusing imgNodes in the same manner.每当我们在视图中点击n - 1时,我还计划使用它来预取下n图像,以相同的方式重用imgNodes

My question are:我的问题是:

  • Is this even a valid idea give 100+ components that will use this idea but only 1 will be visible at a time?这甚至是一个有效的想法,提供 100 多个将使用这个想法的组件,但一次只能看到 1 个?

  • Will I run into memory issues by doing this?这样做我会遇到内存问题吗? I am assuming that imgNodes will be garbage collected when the component is unmounted.我假设在卸载组件时imgNodes将被垃圾收集。

We are using redux so I could save these images in the store but that seems like I am handling the caching instead of leveraging the browser's natural cache.我们正在使用redux ,因此我可以将这些图像保存在商店中,但这似乎是我在处理缓存而不是利用浏览器的自然缓存。

How bad of an idea is this?这是多么糟糕的想法?

You don't need to do it in all of your components. 您无需在所有组件中执行此操作。 As soon as an image is downloaded it gets cached by the browser and will be accessible in all components, so you can do this only once somewhere in a high-level component. 下载图像后,它会立即被浏览器缓存,并且可以在所有组件中访问,因此您只能在高级组件中的某个位置执行此操作。

I don't know what exactly UX you are trying to create by caching images, however, your code only initiates downloading images but doesn't know whether an image is being downloaded, has been downloaded successfully or even failed. 我不知道你试图通过缓存图像创建什么样的UX,但是,你的代码只会启动下载图像,但不知道图像是否正在下载,是否已成功下载甚至失败。 So, for example, you want to show a button to change images or add a class to a component only when the images have been downloaded (to make it smooth), your current code may let you down. 因此,例如,您想要显示一个按钮来更改图像或仅在下载图像时将类添加到组件(为了使图像平滑),您当前的代码可能会让您失望。

You may want to resolve this with Promises. 您可能希望使用Promises解决此问题。

// create an utility function somewhere
const checkImage = path =>
    new Promise(resolve => {
        const img = new Image()
        img.onload = () => resolve(path)
        img.onerror = () => reject()

        img.src = path
    })

...

// then in your component
class YourComponent extends Component {

    this.state = { imagesLoaded: false }

    componentDidMount = () =>
        Promise.all(
            R.take(limit, imgUrls).map(checkImage)
        ).then(() => this.setState(() => ({ imagesLoaded: true })),
               () => console.error('could not load images'))

    render = () =>
        this.state.imagesLoaded
            ? <BeautifulComponent />
            : <Skeleton />
}

Regarding memory consumption — I don't think anything bad will happen. 关于内存消耗 - 我认为不会发生任何不好的事情。 Browsers normally limit the number of parallel xhr requests, so you won't be able to create a gigantic heap usage spike to crash anything, as unused images will garbage collected (yet, preserved in browser cache). 浏览器通常会限制并行xhr请求的数量,因此您将无法创建巨大的堆使用峰值来崩溃任何内容,因为未使用的图像将被垃圾收集(但仍保留在浏览器缓存中)。

Redux store is a place to store the app state, not the app assets, but anyway you won't be able to store any actual images there. Redux商店是存储应用程序状态的地方,而不是应用程序资产,但无论如何,您将无法存储任何实际图像。

Please Check this go with the more traditional approach, preloading the images into the browser cache.请使用更传统的方法进行检查,将图像预加载到浏览器缓存中。

https://jack72828383883.medium.com/how-to-preload-images-into-cache-in-react-js-ff1642708240 https://jack72828383883.medium.com/how-to-preload-images-into-cache-in-react-js-ff1642708240

This is simple and works fine:这很简单并且工作正常:

//arraySrcs=["myImage1.png","myImage2.jpg", "myImage3.jpg", etc]

{arraySrcs.map((e) => (
    <img src={e} style={{ display: "none" }} />
  ))}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM