Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(next/image)!: mark onLoadingComplete as deprecated in favor of onLoad #56944

Merged
44 changes: 23 additions & 21 deletions docs/02-app/02-api-reference/01-components/image.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -40,24 +40,24 @@ export default function Page() {
Here's a summary of the props available for the Image Component:

<div style={{ overflowX: 'auto', width: '100%' }}>
| Prop | Example | Type | Required |
| ----------------------------------------- | ------------------------------------ | --------------- | -------- |
| [`src`](#src) | `src="/profile.png"` | String | Yes |
| [`width`](#width) | `width={500}` | Integer (px) | Yes |
| [`height`](#height) | `height={500}` | Integer (px) | Yes |
| [`alt`](#alt) | `alt="Picture of the author"` | String | Yes |
| [`loader`](#loader) | `loader={imageLoader}` | Function | - |
| [`fill`](#fill) | `fill={true}` | Boolean | - |
| [`sizes`](#sizes) | `sizes="(max-width: 768px) 100vw"` | String | - |
| [`quality`](#quality) | `quality={80}` | Integer (1-100) | - |
| [`priority`](#priority) | `priority={true}` | Boolean | - |
| [`placeholder`](#placeholder) | `placeholder="blur"` | String | - |
| [`style`](#style) | `style={{objectFit: "contain"}}` | Object | - |
| [`onLoadingComplete`](#onloadingcomplete) | `onLoadingComplete={img => done())}` | Function | - |
| [`onLoad`](#onload) | `onLoad={event => done())}` | Function | - |
| [`onError`](#onerror) | `onError(event => fail()}` | Function | - |
| [`loading`](#loading) | `loading="lazy"` | String | - |
| [`blurDataURL`](#blurdataurl) | `blurDataURL="data:image/jpeg..."` | String | - |
| Prop | Example | Type | Status |
| ----------------------------------------- | ------------------------------------ | --------------- | ---------- |
| [`src`](#src) | `src="/profile.png"` | String | Required |
| [`width`](#width) | `width={500}` | Integer (px) | Required |
| [`height`](#height) | `height={500}` | Integer (px) | Required |
| [`alt`](#alt) | `alt="Picture of the author"` | String | Required |
| [`loader`](#loader) | `loader={imageLoader}` | Function | - |
| [`fill`](#fill) | `fill={true}` | Boolean | - |
| [`sizes`](#sizes) | `sizes="(max-width: 768px) 100vw"` | String | - |
| [`quality`](#quality) | `quality={80}` | Integer (1-100) | - |
| [`priority`](#priority) | `priority={true}` | Boolean | - |
| [`placeholder`](#placeholder) | `placeholder="blur"` | String | - |
| [`style`](#style) | `style={{objectFit: "contain"}}` | Object | - |
| [`onLoadingComplete`](#onloadingcomplete) | `onLoadingComplete={img => done())}` | Function | Deprecated |
| [`onLoad`](#onload) | `onLoad={event => done())}` | Function | - |
| [`onError`](#onerror) | `onError(event => fail()}` | Function | - |
| [`loading`](#loading) | `loading="lazy"` | String | - |
| [`blurDataURL`](#blurdataurl) | `blurDataURL="data:image/jpeg..."` | String | - |
</div>

## Required Props
Expand Down Expand Up @@ -286,6 +286,8 @@ Remember that the required width and height props can interact with your styling
<Image onLoadingComplete={(img) => console.log(img.naturalWidth)} />
```

> **Warning**: Deprecated since Next.js 14 in favor of [`onLoad`](#onload).

A callback function that is invoked once the image is completely loaded and the [placeholder](#placeholder) has been removed.

The callback function will be called with one argument, a reference to the underlying `<img>` element.
Expand All @@ -302,9 +304,9 @@ The callback function will be called with one argument, a reference to the under
<Image onLoad={(e) => console.log(e.target.naturalWidth)} />
```

A callback function that is invoked when the image is loaded.
A callback function that is invoked once the image is completely loaded and the [placeholder](#placeholder) has been removed.

The load event might occur before the image placeholder is removed and the image is fully decoded. If you want to wait until the image has fully loaded, use [`onLoadingComplete`](#onloadingcomplete) instead.
The callback function will be called with one argument, the Event which has a `target` that references the underlying `<img>` element.

<AppOnly>

Expand Down Expand Up @@ -445,7 +447,7 @@ The `**` syntax does not work in the middle of the pattern.

### `domains`

> **Warning**: We recommend configuring strict [`remotePatterns`](#remotepatterns) instead of `domains` in order to protect your application from malicious users. Only use `domains` if you own all the content served from the domain.
> **Warning**: Deprecated since Next.js 14. We recommend configuring strict [`remotePatterns`](#remotepatterns) instead of `domains` in order to protect your application from malicious users. Only use `domains` if you own all the content served from the domain.

Similar to [`remotePatterns`](#remotepatterns), the `domains` configuration can be used to provide a list of allowed hostnames for external images.

Expand Down
2 changes: 1 addition & 1 deletion examples/with-cloudinary/components/SharedModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export default function SharedModal({
height={navigation ? 853 : 1280}
priority
alt="Next.js Conf image"
onLoadingComplete={() => setLoaded(true)}
onLoad={() => setLoaded(true)}
/>
</motion.div>
</AnimatePresence>
Expand Down
2 changes: 1 addition & 1 deletion examples/with-sfcc/components/ProductCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default function ProductCard({ product }) {
? 'scale-110 blur-2xl grayscale'
: 'scale-100 blur-0 grayscale-0'
)}
onLoadingComplete={() => setLoading(false)}
onLoad={() => setLoading(false)}
/>
</div>
<div className="mt-4 flex items-center justify-between text-base font-medium text-gray-900">
Expand Down
12 changes: 11 additions & 1 deletion packages/next/src/shared/lib/get-img-props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ export type ImageProps = Omit<
placeholder?: PlaceholderValue
blurDataURL?: string
unoptimized?: boolean
/**
* @deprecated Use `onLoad` instead.
* @see https://nextjs.org/docs/app/api-reference/components/image#onload
*/
onLoadingComplete?: OnLoadingComplete
/**
* @deprecated Use `fill` prop instead of `layout="fill"` or change import to `next/legacy/image`.
Expand Down Expand Up @@ -500,7 +504,7 @@ export function getImgProps(
}
if ('ref' in rest) {
warnOnce(
`Image with src "${src}" is using unsupported "ref" property. Consider using the "onLoadingComplete" property instead.`
`Image with src "${src}" is using unsupported "ref" property. Consider using the "onLoad" property instead.`
)
}

Expand All @@ -523,6 +527,12 @@ export function getImgProps(
}
}

if (onLoadingComplete) {
warnOnce(
`Image with src "${src}" is using deprecated "onLoadingComplete" property. Please use the "onLoad" property instead.`
)
}

for (const [legacyKey, legacyValue] of Object.entries({
layout,
objectFit,
Expand Down
9 changes: 9 additions & 0 deletions test/integration/next-image-new/app-dir/test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,15 @@ function runTests(mode) {
() => browser.eval(`document.getElementById("msg9").textContent`),
'loaded 1 img9 with dimensions 400x400'
)

if (mode === 'dev') {
const warnings = (await browser.log('browser'))
.map((log) => log.message)
.join('\n')
expect(warnings).toMatch(
/Image with src "(.*)" is using deprecated "onLoadingComplete" property/gm
)
}
})

it('should callback native onLoad with sythetic event', async () => {
Expand Down
9 changes: 9 additions & 0 deletions test/integration/next-image-new/default/test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,15 @@ function runTests(mode) {
() => browser.eval(`document.getElementById("msg9").textContent`),
'loaded 1 img9 with dimensions 400x400'
)

if (mode === 'dev') {
const warnings = (await browser.log('browser'))
.map((log) => log.message)
.join('\n')
expect(warnings).toMatch(
/Image with src "(.*)" is using deprecated "onLoadingComplete" property/gm
)
}
})

it('should callback native onLoad with sythetic event', async () => {
Expand Down
Loading