NextJS:从缓存加载的图像不会触发onLoad事件

时间:2020-01-17 12:44:59

标签: javascript reactjs next.js

出于搜索引擎优化和社交媒体链接的原因,我目前正在将ReactJS客户端呈现的应用程序转换为NextJS应用程序。

转换后的组件之一(基本上是等待其完成加载然后逐渐消失的图像)在NextJS环境中使用后无法正常工作。

它的行为如下:

启用缓存:

  • 第一次加载图像并触发onLoad事件,从而显示图像。
  • 第二次隐藏图像,因为从缓存加载图像时不会触发onLoad事件。

使用devtools禁用了缓存:

  • onLoad事件始终有效,因为永远不会从缓存中提供图像。

预期的行为以及以前仅使用ReactJS即可实现的行为:

  • onLoad事件应触发是否从缓存中加载了图像。

不使用React时,通常是由于有人在定义src函数之前设置了图像onload引起的:

let img = new Image()
img.src = "img.jpg"
img.onload = () => console.log("Image loaded.")

应该是:

let img = new Image()
img.onload = () => console.log("Image loaded.")
img.src = "img.jpg"

以下是简化的代码,在NextJS中会导致相同的问题:

import React, { useState } from "react"

const Home = () => {
    const [loaded, setLoaded] = useState(false)

    const homeStyles = {
        width: "100%",
        height: "96vh",
        backgroundColor: "black"
    }

    const imgStyles = {
        width: "100%",
        height: "100%",
        objectFit: "cover",
        opacity: loaded ? 1 : 0
    }

    const handleLoad = () => {
        console.log("Loaded")
        setLoaded(true)
    }

    return (
        <div className="Home" style={homeStyles}>
            <img alt=""
                onLoad={handleLoad}
                src="https://images.unsplash.com/photo-1558981001-5864b3250a69?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80"
                style={imgStyles}
            />
        </div>
    )
}

export default Home

3 个答案:

答案 0 :(得分:5)

由于有人的建议,我最终使用ImageObject.complete作为解决方法。

我使用useRef引用了图像,并检查了image.current.complete === true是否安装在组件上。

代码如下:

import React, { useEffect, useRef, useState } from "react"

const Home = () => {
    const [loaded, setLoaded] = useState(false)

    const image = useRef()

    const homeStyles = {
        width: "100%",
        height: "96vh",
        backgroundColor: "black"
    }

    const imgStyles = {
        width: "100%",
        height: "100%",
        objectFit: "cover",
        opacity: loaded ? 1 : 0
    }

    const handleLoad = () => setLoaded(true)

    useEffect(() => {
        if (image.current.complete) setLoaded(true)
    }, [])

    return (
        <div className="Home" style={homeStyles}>
            <img alt=""
                ref={image}
                onLoad={handleLoad}
                src="https://images.unsplash.com/photo-1558981001-5864b3250a69?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80"
                style={imgStyles}
            />
        </div>
    )
}

export default Home

答案 1 :(得分:1)

如果您使用的是 nextjs 10 中的新 Image 组件,该组件不支持前向引用,您可以使用

修改解决方法
const [loaded, setLoaded] = useState(false)
const ref = useRef<HTMLDivElement>(null)
useEffect(() => {
  if ((ref.current?.firstChild?.firstChild as HTMLImageElement | undefined)?.complete) {
    setLoaded(true)
  }
}, [])

return <div ref={ref}>
         <Image src={src} 
           onLoad={() => setLoaded(true)}/>
       </div>

答案 2 :(得分:1)

从 Next.js v11.0.2-canary.4 开始,可以直接使用 onLoadingComplete 属性。

<Image src={src} onLoadingComplete={() => setLoaded(true)} />

这与其他选项相比如何??

  • 您可以继续使用很棒的 next/image 组件而不是未优化的 img 标签,而无需任何额外的代码或自己处理引用。
相关问题