【问题标题】:How To Cache Images in React?如何在 React 中缓存图像?
【发布时间】:2017-09-24 11:20:36
【问题描述】:

假设我有一个这样的 url 列表:

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

我想预取其中的n,以便图像之间的转换更快。我现在在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;
      });
    }

imgNodes 的定义如下:

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

还有来自ramdatimesziptake

现在当我在里面使用这些网址时,会像这样:

<img src={url} />

它会根据EtagExpire 标记访问浏览器缓存,无论在哪里使用url。我还计划在我们在视图内点击n - 1 时使用它来预取下一个n 图像,以同样的方式重用imgNodes

我的问题是:

  • 这是否是一个有效的想法,提供 100 多个将使用此想法但一次只能看到 1 个的组件?

  • 这样做会遇到内存问题吗?我假设在卸载组件时imgNodes 将被垃圾收集。

我们正在使用redux,因此我可以将这些图像保存在商店中,但这似乎是我在处理缓存而不是利用浏览器的自然缓存。

这是多么糟糕的想法?

【问题讨论】:

  • 你有没有带着这个去任何地方?我有兴趣...
  • @MathieuK。我们具有与上述基本相同的结构/接口,利用正常的 HTTP 缓存。
  • 所以你依赖浏览器/HTTP的默认行为?
  • 我依赖于我理解 HTML 的 img 规范的方式。听起来好像是说一旦您要求浏览器获取资源,如果您再次询问并且它在您的已知图像列表中,它就不必重新请求该资源。 dev.w3.org/html5/spec-preview/… 我希望如果我误解了,浏览器/HTTP 缓存会说不要重新获取。

标签: javascript reactjs caching dom


【解决方案1】:

您不需要在所有组件中都这样做。下载图像后,浏览器会对其进行缓存,并且可以在所有组件中访问,因此您只能在高级组件的某个位置执行此操作。

我不知道您试图通过缓存图像来创建什么样的用户体验,但是,您的代码仅启动下载图像,但不知道图像是否正在下载、是否已成功下载或什至失败。因此,例如,您希望仅在图像已下载(以使其流畅)时显示更改图像或向组件添加类的按钮,您当前的代码可能会让您失望。

你可能想用 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 />
}

关于内存消耗——我认为不会发生任何不好的事情。浏览器通常会限制并行 xhr 请求的数量,因此您将无法创建巨大的堆使用峰值来崩溃任何东西,因为未使用的图像将被垃圾收集(但保留在浏览器缓存中)。

Redux 商店是存储应用状态的地方,而不是应用资产,但无论如何您都无法在其中存储任何实际图像。

【讨论】:

    【解决方案2】:

    这很简单,效果很好:

    //arraySrcs=["myImage1.png","myImage2.jpg", "myImage3.jpg", etc]
    
    {arraySrcs.map((e) => (
        <img src={e} style={{ display: "none" }} />
      ))}
    

    【讨论】:

    • Tomerikoo 为什么要编辑表情符号、粗体字母和链接?
    • 我猜是因为这是使用样式和图标来引起注意(而不是为答案增加价值),并且链接也没有为答案增加任何价值,基本上只是广告对于不相关的事情。
    猜你喜欢
    • 2017-09-25
    • 2019-11-30
    • 1970-01-01
    • 2023-03-17
    • 2018-06-17
    • 2012-03-08
    • 2015-12-11
    • 2015-03-25
    • 2012-05-01
    相关资源
    最近更新 更多