diff --git a/packages/next/client/future/image.tsx b/packages/next/client/future/image.tsx index 6860dd5f4cc9..224a91402d48 100644 --- a/packages/next/client/future/image.tsx +++ b/packages/next/client/future/image.tsx @@ -48,7 +48,7 @@ type ImageLoaderPropsWithConfig = ImageLoaderProps & { } type PlaceholderValue = 'blur' | 'empty' - +type OnLoad = React.ReactEventHandler | undefined type OnLoadingComplete = (img: HTMLImageElement) => void type ImgElementStyle = NonNullable @@ -128,6 +128,7 @@ type ImageElementProps = Omit & { unoptimized: boolean loader: ImageLoaderWithConfig placeholder: PlaceholderValue + onLoadRef: React.MutableRefObject onLoadingCompleteRef: React.MutableRefObject setBlurComplete: (b: boolean) => void setShowAltText: (b: boolean) => void @@ -245,6 +246,7 @@ function handleLoading( img: ImgElementWithDataProp, src: string, placeholder: PlaceholderValue, + onLoadRef: React.MutableRefObject, onLoadingCompleteRef: React.MutableRefObject, setBlurComplete: (b: boolean) => void ) { @@ -265,6 +267,30 @@ function handleLoading( if (placeholder === 'blur') { setBlurComplete(true) } + if (onLoadRef?.current) { + const event = new Event('load') + Object.defineProperty(event, 'target', { writable: false, value: img }) + let prevented = false + let stopped = false + const sytheticEvent = { + ...event, + nativeEvent: event, + currentTarget: img, + target: img, + isDefaultPrevented: () => prevented, + isPropagationStopped: () => stopped, + persist: () => {}, + preventDefault: () => { + prevented = true + event.preventDefault() + }, + stopPropagation: () => { + stopped = true + event.stopPropagation() + }, + } + onLoadRef.current(sytheticEvent) + } if (onLoadingCompleteRef?.current) { onLoadingCompleteRef.current(img) } @@ -331,6 +357,7 @@ const ImageElement = ({ config, unoptimized, loader, + onLoadRef, onLoadingCompleteRef, setBlurComplete, setShowAltText, @@ -397,6 +424,7 @@ const ImageElement = ({ img, srcString, placeholder, + onLoadRef, onLoadingCompleteRef, setBlurComplete ) @@ -405,6 +433,7 @@ const ImageElement = ({ [ srcString, placeholder, + onLoadRef, onLoadingCompleteRef, setBlurComplete, onError, @@ -416,12 +445,10 @@ const ImageElement = ({ img, srcString, placeholder, + onLoadRef, onLoadingCompleteRef, setBlurComplete ) - if (onLoad) { - onLoad(event) - } }} onError={(event) => { // if the real image fails to load, this will ensure "alt" is visible @@ -515,6 +542,7 @@ export default function Image({ height, fill, style, + onLoad, onLoadingComplete, placeholder = 'empty', blurDataURL, @@ -837,6 +865,12 @@ export default function Image({ crossOrigin: rest.crossOrigin, } + const onLoadRef = useRef(onLoad) + + useEffect(() => { + onLoadRef.current = onLoad + }, [onLoad]) + const onLoadingCompleteRef = useRef(onLoadingComplete) useEffect(() => { @@ -859,6 +893,7 @@ export default function Image({ placeholder, loader, srcString, + onLoadRef, onLoadingCompleteRef, setBlurComplete, setShowAltText, diff --git a/test/integration/image-future/default/pages/on-load.js b/test/integration/image-future/default/pages/on-load.js index 8473276bcc00..2bdd8d6d4e01 100644 --- a/test/integration/image-future/default/pages/on-load.js +++ b/test/integration/image-future/default/pages/on-load.js @@ -2,6 +2,7 @@ import { useState } from 'react' import Image from 'next/future/image' const Page = () => { + const [idToCount, setIdToCount] = useState({}) const [clicked, setClicked] = useState(false) const red = @@ -10,10 +11,7 @@ const Page = () => { return (

Test onLoad

-

- This is the native onLoad which doesn't work as many places as - onLoadingComplete -

+

This is the native onLoad

@@ -23,6 +21,8 @@ const Page = () => { src={clicked ? '/test.jpg' : red} width="128" height="128" + idToCount={idToCount} + setIdToCount={setIdToCount} /> { placeholder={clicked ? 'blur' : 'empty'} width="256" height="256" + idToCount={idToCount} + setIdToCount={setIdToCount} /> { src={clicked ? '/test.svg' : red} width="1200" height="1200" + idToCount={idToCount} + setIdToCount={setIdToCount} /> { src={clicked ? '/test.ico' : red} width={200} height={200} + idToCount={idToCount} + setIdToCount={setIdToCount} /> + +