mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-01 10:01:04 -04:00
fix(client): defer MobileAppModal rendering until after first browser paint (#67154)
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import { renderToString } from 'react-dom/server';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import {
|
||||
describe,
|
||||
@@ -75,6 +76,14 @@ describe('MobileAppModal', () => {
|
||||
expect(screen.getByRole('dialog')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not render before mount', () => {
|
||||
// useEffect does not run during server-side rendering, so the 'mounted'
|
||||
// flag stays false and the component should produce no output.
|
||||
expect(
|
||||
renderToString(<MobileAppModal superBlock={MOBILE_SUPERBLOCK} />)
|
||||
).toBe('');
|
||||
});
|
||||
|
||||
it('does not render on a desktop OS', () => {
|
||||
Object.defineProperty(navigator, 'userAgent', {
|
||||
value: DESKTOP_UA,
|
||||
|
||||
@@ -58,6 +58,20 @@ function MobileAppModal({
|
||||
const os = detectOS();
|
||||
const [dismissed, setDismissed] = useState(isDismissedFor30Days);
|
||||
|
||||
// Defer rendering until after the first browser paint. On a direct page
|
||||
// load the component hydrates before the browser has computed layout, so
|
||||
// document.documentElement.clientWidth is 0. The Modal's scroll-lock
|
||||
// utility calculates the scrollbar compensation as
|
||||
// window.innerWidth - clientWidth, which produces window.innerWidth when
|
||||
// clientWidth is 0, and stamps that value as padding-right on <html>,
|
||||
// breaking the layout. Waiting for useEffect guarantees that layout has
|
||||
// been computed before the modal (and its scroll-lock) opens.
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isProjectPreviewOpen) setDismissed(true);
|
||||
}, [isProjectPreviewOpen]);
|
||||
@@ -73,7 +87,13 @@ function MobileAppModal({
|
||||
const storeName =
|
||||
os === 'ios' ? t('mobile-app-modal.ios') : t('mobile-app-modal.android');
|
||||
|
||||
if (os === 'other' || !isAvailable || isProjectPreviewOpen || dismissed)
|
||||
if (
|
||||
!mounted ||
|
||||
os === 'other' ||
|
||||
!isAvailable ||
|
||||
isProjectPreviewOpen ||
|
||||
dismissed
|
||||
)
|
||||
return null;
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user