diff --git a/packages/next/client/use-intersection.tsx b/packages/next/client/use-intersection.tsx index afcc29004fb0c..3f93811acaffb 100644 --- a/packages/next/client/use-intersection.tsx +++ b/packages/next/client/use-intersection.tsx @@ -23,7 +23,7 @@ type Observer = { elements: Map } -const hasIntersectionObserver = typeof IntersectionObserver !== 'undefined' +const hasIntersectionObserver = typeof IntersectionObserver === 'function' export function useIntersection({ rootRef, @@ -34,9 +34,10 @@ export function useIntersection({ const unobserve = useRef() const [visible, setVisible] = useState(false) - const [root, setRoot] = useState(rootRef ? rootRef.current : null) - const setRef = useCallback( - (el: T | null) => { + const [element, setElement] = useState(null) + + useEffect(() => { + if (hasIntersectionObserver) { if (unobserve.current) { unobserve.current() unobserve.current = undefined @@ -44,34 +45,31 @@ export function useIntersection({ if (isDisabled || visible) return - if (el && el.tagName) { + if (element && element.tagName) { unobserve.current = observe( - el, + element, (isVisible) => isVisible && setVisible(isVisible), - { root, rootMargin } + { root: rootRef?.current, rootMargin } ) } - }, - [isDisabled, root, rootMargin, visible] - ) - - const resetVisible = useCallback(() => { - setVisible(false) - }, []) - useEffect(() => { - if (!hasIntersectionObserver) { + return () => { + unobserve.current?.() + unobserve.current = undefined + } + } else { if (!visible) { const idleCallback = requestIdleCallback(() => setVisible(true)) return () => cancelIdleCallback(idleCallback) } } - }, [visible]) + }, [element, isDisabled, rootMargin, rootRef, visible]) - useEffect(() => { - if (rootRef) setRoot(rootRef.current) - }, [rootRef]) - return [setRef, visible, resetVisible] + const resetVisible = useCallback(() => { + setVisible(false) + }, []) + + return [setElement, visible, resetVisible] } function observe( @@ -91,7 +89,7 @@ function observe( if (elements.size === 0) { observer.disconnect() observers.delete(id) - let index = idList.findIndex( + const index = idList.findIndex( (obj) => obj.root === id.root && obj.margin === id.margin ) if (index > -1) { @@ -110,18 +108,16 @@ function createObserver(options: UseIntersectionObserverInit): Observer { root: options.root || null, margin: options.rootMargin || '', } - let existing = idList.find( + const existing = idList.find( (obj) => obj.root === id.root && obj.margin === id.margin ) - let instance + let instance: Observer | undefined + if (existing) { instance = observers.get(existing) - } else { - instance = observers.get(id) - idList.push(id) - } - if (instance) { - return instance + if (instance) { + return instance + } } const elements = new Map() @@ -134,14 +130,13 @@ function createObserver(options: UseIntersectionObserverInit): Observer { } }) }, options) - - observers.set( + instance = { id, - (instance = { - id, - observer, - elements, - }) - ) + observer, + elements, + } + + idList.push(id) + observers.set(id, instance) return instance } diff --git a/test/integration/image-component/basic/pages/lazy.js b/test/integration/image-component/basic/pages/lazy.js index 5194d90f29094..55f441b6ff496 100644 --- a/test/integration/image-component/basic/pages/lazy.js +++ b/test/integration/image-component/basic/pages/lazy.js @@ -1,6 +1,5 @@ import React from 'react' import Image from 'next/image' -import Link from 'next/link' const Lazy = () => { return ( @@ -54,9 +53,6 @@ const Lazy = () => { width={800} lazyBoundary="0px 0px 500px 0px" > - - observer - ) } diff --git a/test/integration/image-component/basic/test/index.test.js b/test/integration/image-component/basic/test/index.test.js index 3a44542c2a89c..9f308f327e8cf 100644 --- a/test/integration/image-component/basic/test/index.test.js +++ b/test/integration/image-component/basic/test/index.test.js @@ -384,19 +384,6 @@ describe('Image Component Tests', () => { browser = null }) lazyLoadingTests() - it('should automatically load images if observer does not exist', async () => { - browser = await webdriver(appPort, '/missing-observer') - expect( - await browser.elementById('lazy-no-observer').getAttribute('src') - ).toBe( - 'https://example.com/myaccount/foox.jpg?auto=format&fit=max&w=2000' - ) - expect( - await browser.elementById('lazy-no-observer').getAttribute('srcset') - ).toBe( - 'https://example.com/myaccount/foox.jpg?auto=format&fit=max&w=1024 1x, https://example.com/myaccount/foox.jpg?auto=format&fit=max&w=2000 2x' - ) - }) }) describe('Client-side Lazy Loading Tests', () => { beforeAll(async () => { @@ -408,20 +395,5 @@ describe('Image Component Tests', () => { browser = null }) lazyLoadingTests() - it('should automatically load images if observer does not exist', async () => { - await browser.waitForElementByCss('#observerlink').click() - await waitFor(500) - browser = await webdriver(appPort, '/missing-observer') - expect( - await browser.elementById('lazy-no-observer').getAttribute('src') - ).toBe( - 'https://example.com/myaccount/foox.jpg?auto=format&fit=max&w=2000' - ) - expect( - await browser.elementById('lazy-no-observer').getAttribute('srcset') - ).toBe( - 'https://example.com/myaccount/foox.jpg?auto=format&fit=max&w=1024 1x, https://example.com/myaccount/foox.jpg?auto=format&fit=max&w=2000 2x' - ) - }) }) }) diff --git a/test/integration/image-component/no-intersection-observer-fallback/next.config.js b/test/integration/image-component/no-intersection-observer-fallback/next.config.js new file mode 100644 index 0000000000000..5d8fb97cde549 --- /dev/null +++ b/test/integration/image-component/no-intersection-observer-fallback/next.config.js @@ -0,0 +1,8 @@ +module.exports = { + images: { + deviceSizes: [480, 1024, 1600, 2000], + imageSizes: [16, 32, 48, 64], + path: 'https://example.com/myaccount/', + loader: 'imgix', + }, +} diff --git a/test/integration/image-component/no-intersection-observer-fallback/pages/_document.js b/test/integration/image-component/no-intersection-observer-fallback/pages/_document.js new file mode 100644 index 0000000000000..1be962b3daeb6 --- /dev/null +++ b/test/integration/image-component/no-intersection-observer-fallback/pages/_document.js @@ -0,0 +1,19 @@ +import Document, { Html, Head, Main, NextScript } from 'next/document' + +export default class MyDocument extends Document { + render() { + return ( + + +