How To Cache Images in React?

眉间皱痕 提交于 2020-12-01 10:07:19

问题


Suppose I have a list of url's like so :

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

And I want to prefetch n of those so that transitioning between images is faster. What I am doing now in componentWillMount is the following:

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: times(_ => new window.Image(), props.prefetchLimit),

and times, zip, and take coming from 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. 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.

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?

  • Will I run into memory issues by doing this? I am assuming that imgNodes will be garbage collected when the component is unmounted.

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.

How bad of an idea is this?


回答1:


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. 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.

// 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).

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.



来源:https://stackoverflow.com/questions/43644633/how-to-cache-images-in-react

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!