diff --git a/packages/@react-aria/utils/src/useViewportSize.ts b/packages/@react-aria/utils/src/useViewportSize.ts index 30fc9d26385..ed6f6f765e5 100644 --- a/packages/@react-aria/utils/src/useViewportSize.ts +++ b/packages/@react-aria/utils/src/useViewportSize.ts @@ -26,6 +26,15 @@ export function useViewportSize(): ViewportSize { let [size, setSize] = useState(() => isSSR ? {width: 0, height: 0} : getViewportSize()); useEffect(() => { + let updateSize = (newSize: ViewportSize) => { + setSize(size => { + if (newSize.width === size.width && newSize.height === size.height) { + return size; + } + return newSize; + }); + }; + // Use visualViewport api to track available height even on iOS virtual keyboard opening let onResize = () => { // Ignore updates when zoomed. @@ -33,13 +42,7 @@ export function useViewportSize(): ViewportSize { return; } - setSize(size => { - let newSize = getViewportSize(); - if (newSize.width === size.width && newSize.height === size.height) { - return size; - } - return newSize; - }); + updateSize(getViewportSize()); }; // When closing the keyboard, iOS does not fire the visual viewport resize event until the animation is complete. @@ -54,18 +57,14 @@ export function useViewportSize(): ViewportSize { // Wait one frame to see if a new element gets focused. frame = requestAnimationFrame(() => { if (!document.activeElement || !willOpenKeyboard(document.activeElement)) { - setSize(size => { - let newSize = {width: window.innerWidth, height: window.innerHeight}; - if (newSize.width === size.width && newSize.height === size.height) { - return size; - } - return newSize; - }); + updateSize({width: window.innerWidth, height: window.innerHeight}); } }); } }; + updateSize(getViewportSize()); + window.addEventListener('blur', onBlur, true); if (!visualViewport) { diff --git a/packages/@react-aria/utils/test/useViewportSize.ssr.test.tsx b/packages/@react-aria/utils/test/useViewportSize.ssr.test.tsx index a5dcf31ae6c..e14deb7b3bc 100644 --- a/packages/@react-aria/utils/test/useViewportSize.ssr.test.tsx +++ b/packages/@react-aria/utils/test/useViewportSize.ssr.test.tsx @@ -10,7 +10,7 @@ * governing permissions and limitations under the License. */ -import {testSSR} from '@react-spectrum/test-utils-internal'; +import {screen, testSSR} from '@react-spectrum/test-utils-internal'; describe('useViewportSize SSR', () => { it('should render without errors', async () => { @@ -25,4 +25,21 @@ describe('useViewportSize SSR', () => { `); }); + + it('should update dimensions after hydration', async () => { + await testSSR(__filename, ` + import {useViewportSize} from '../src'; + + function Viewport() { + let size = useViewportSize(); + return
{size.width}x{size.height}
; + } + + + `, () => { + expect(screen.getByTestId('viewport')).toHaveTextContent('0x0'); + }); + + expect(screen.getByTestId('viewport')).not.toHaveTextContent('0x0'); + }); });