Changeset View
Standalone View
landing/landing.react.js
// @flow | // @flow | ||||
import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { useRouteMatch } from 'react-router-dom'; | import { useRouteMatch } from 'react-router-dom'; | ||||
import { | import { | ||||
ModalProvider, | ModalProvider, | ||||
useModalContext, | useModalContext, | ||||
} from 'lib/components/modal-provider.react.js'; | } from 'lib/components/modal-provider.react.js'; | ||||
import AppLanding from './app-landing.react.js'; | import AppLanding from './app-landing.react.js'; | ||||
import Footer from './footer.react.js'; | import Footer from './footer.react.js'; | ||||
import Header from './header.react.js'; | import Header, { HEADER_BREAKPOINT } from './header.react.js'; | ||||
import Investors from './investors.react.js'; | import Investors from './investors.react.js'; | ||||
import Keyservers from './keyservers.react.js'; | import Keyservers from './keyservers.react.js'; | ||||
import css from './landing.css'; | import css from './landing.css'; | ||||
import MobileNav from './mobile-nav.react.js'; | import MobileNav from './mobile-nav.react.js'; | ||||
import Privacy from './privacy.react.js'; | import Privacy from './privacy.react.js'; | ||||
import QR from './qr.react.js'; | import QR from './qr.react.js'; | ||||
import SIWE from './siwe.react.js'; | import SIWE from './siwe.react.js'; | ||||
import Support from './support.react.js'; | import Support from './support.react.js'; | ||||
Show All 23 Lines | () => | ||||
modalContext.modals.map(([modal, key]) => ( | modalContext.modals.map(([modal, key]) => ( | ||||
<React.Fragment key={key}>{modal}</React.Fragment> | <React.Fragment key={key}>{modal}</React.Fragment> | ||||
)), | )), | ||||
[modalContext.modals], | [modalContext.modals], | ||||
); | ); | ||||
const [showMobileNav, setShowMobileNav] = React.useState<boolean>(false); | const [showMobileNav, setShowMobileNav] = React.useState<boolean>(false); | ||||
React.useEffect(() => { | |||||
const handleResize = () => { | |||||
if (window.innerWidth > HEADER_BREAKPOINT && showMobileNav) { | |||||
setShowMobileNav(false); | |||||
} | |||||
}; | |||||
atul: Do we need to define this function within the `useEffect(...)`? | |||||
ginsuAuthorUnsubmitted Done Inline ActionsWe want to make sure that we use showMobileNav directly in the useEffect to ensure that the most current state value of showMobileNav is being used. If we put the showMobileNav in the callback we could run into the situation where the handleResize function created in a particular render will always refer to the showMobileNav value from that specific render, and this could be an outdated value. With this in mind we could change the effect to look like this const handleResize = React.useCallback(() => { if (window.innerWidth > HEADER_BREAKPOINT) { setShowMobileNav(false); } }, [setShowMobileNav]); React.useEffect(() => { if (showMobileNav) { window.addEventListener('resize', handleResize); } return () => { window.removeEventListener('resize', handleResize); }; }, [handleResize, showMobileNav]); However with this solution we may be removing an event listener even when it's added. Technically there is no harm/risk in doing so, but it is a bit strange and considered an antipattern. ginsu: We want to make sure that we use `showMobileNav` directly in the `useEffect` to ensure that the… | |||||
ashoatUnsubmitted Not Done Inline Actions
Pretty sure you have the exact same problem in your current implementation? You're not declaring any refs, so my intuition tells me there can't be any difference in approaches. Your handleResize function is going to be bound with the value of showMobileNav at the time the effect was run. This strongly smells like a core misunderstanding, not just about React but about how variables work in JavaScript.
I don't understand why you think you have to do that. Can't you just do this? const handleResize = React.useCallback(() => { if (window.innerWidth > HEADER_BREAKPOINT) { setShowMobileNav(false); } }, [setShowMobileNav]); React.useEffect(() => { if (showMobileNav) { window.addEventListener('resize', handleResize); return undefined; } return () => { window.removeEventListener('resize', handleResize); }; }, [handleResize, showMobileNav]); ashoat: > If we put the `showMobileNav` in the callback we could run into the situation where the… | |||||
window.addEventListener('resize', handleResize); | |||||
return () => { | |||||
window.removeEventListener('resize', handleResize); | |||||
}; | |||||
}, [showMobileNav, setShowMobileNav]); | |||||
const innerContainerClassName = classNames({ | const innerContainerClassName = classNames({ | ||||
[css.innerContainer]: true, | [css.innerContainer]: true, | ||||
[css.innerContainerMobileNav]: showMobileNav, | [css.innerContainerMobileNav]: showMobileNav, | ||||
}); | }); | ||||
useScrollToTopOnNavigate(); | useScrollToTopOnNavigate(); | ||||
const onPrivacy = useRouteMatch({ path: '/privacy' }); | const onPrivacy = useRouteMatch({ path: '/privacy' }); | ||||
const onTerms = useRouteMatch({ path: '/terms' }); | const onTerms = useRouteMatch({ path: '/terms' }); | ||||
▲ Show 20 Lines • Show All 60 Lines • Show Last 20 Lines |
Do we need to define this function within the useEffect(...)?