diff --git a/docs/api-reference/next/future/image.md b/docs/api-reference/next/future/image.md index 2438cad0c84e..aeeacf7eac26 100644 --- a/docs/api-reference/next/future/image.md +++ b/docs/api-reference/next/future/image.md @@ -43,7 +43,6 @@ Compared to `next/image`, the new `next/future/image` component has the followin - Removes `lazyBoundary` prop since there is no native equivalent - Removes `lazyRoot` prop since there is no native equivalent - Removes `loader` config in favor of [`loader`](#loader) prop -- Note: the [`onError`](#onerror) prop might behave differently ## Known Browser Bugs @@ -316,7 +315,7 @@ The callback function will be called with one argument, an object with the follo A callback function that is invoked when the image is loaded. -Note that the load event might occur before client-side hydration completes, so this callback might not be invoked in that case. +Note that the load event might occur before the placeholder is removed and the image is fully decoded. Instead, use [`onLoadingComplete`](#onloadingcomplete). @@ -324,8 +323,6 @@ Instead, use [`onLoadingComplete`](#onloadingcomplete). A callback function that is invoked if the image fails to load. -Note that the error might occur before client-side hydration completes, so this callback might not be invoked in that case. - ### loading > **Attention**: This property is only meant for advanced usage. Switching an diff --git a/packages/next/client/future/image.tsx b/packages/next/client/future/image.tsx index 81cc5e45d964..5fe483f337fe 100644 --- a/packages/next/client/future/image.tsx +++ b/packages/next/client/future/image.tsx @@ -358,7 +358,14 @@ const ImageElement = ({ loading={loading} style={{ ...imgStyle, ...blurStyle }} ref={useCallback( - (img: ImgElementWithDataProp) => { + (img: ImgElementWithDataProp | null) => { + if (img && onError) { + // If the image has an error before react hydrates, then the error is lost. + // The workaround is to wait until the image is mounted which is after hydration, + // then we set the src again to trigger the error handler (if there was an error). + // eslint-disable-next-line no-self-assign + img.src = img.src + } if (process.env.NODE_ENV !== 'production') { if (img && !srcString) { console.error(`Image is missing required "src" property:`, img) @@ -374,7 +381,13 @@ const ImageElement = ({ ) } }, - [srcString, placeholder, onLoadingCompleteRef, setBlurComplete] + [ + srcString, + placeholder, + onLoadingCompleteRef, + setBlurComplete, + onError, + ] )} onLoad={(event) => { const img = event.currentTarget as ImgElementWithDataProp diff --git a/test/integration/image-future/default/pages/on-error-before-hydration.js b/test/integration/image-future/default/pages/on-error-before-hydration.js new file mode 100644 index 000000000000..ac68b482a3fc --- /dev/null +++ b/test/integration/image-future/default/pages/on-error-before-hydration.js @@ -0,0 +1,22 @@ +import { useState } from 'react' +import Image from 'next/future/image' + +const Page = () => { + const [msg, setMsg] = useState(`default state`) + return ( +
{msg}
+