useIsFocused
Since useIsFocused() only applicable on Native, you can replace it with a custom function on Web.
Create your exports​
hooks/use-is-focused.ts
tsexport {useIsFocused } from '@react-navigation/native'
tsexport {useIsFocused } from '@react-navigation/native'
hooks/use-is-focused.web.ts
tsexport functionuseIsFocused () {return true}
tsexport functionuseIsFocused () {return true}
On Web, screens are always focused when they're mounted.
Import your file​
tsimport { useIsFocused } from 'hooks/use-is-focused'
tsimport { useIsFocused } from 'hooks/use-is-focused'
Custom Web Logic​
This section is a little more advanced. It's relevant if you're using modals with Next Router.
In the above example, we always return true on Web.
One exception might be if there is a shallow routed modal on top of a screen.
For example, say that you have an EditArtist modal that shows when the URL contains a query param like /artists/drake?showsEditModal=true.
If you want to implement this logic, you could do it yourself on Web using a combination of React Context and checking query params with useRouter from next/router.
Create a context​
First, in a file called context/modal-screen create your ModalScreenContext. This will let screens detect if they are a modal or not.
tsimport {createContext } from 'react'Âexport constModalScreenContext =createContext (false)
tsimport {createContext } from 'react'Âexport constModalScreenContext =createContext (false)
Then, your actual Next.js page could look something like this:
tsx// pages/artist/[slug].tsximport { ModalScreenContext } from 'context/modal-screen'import { useRouter } from 'next/router'export default function ArtistPage() {const router = useRouter()return (<><ArtistScreen /><ModalScreenContext.Provider value={true}>{!!router?.query?.showsEditModal && <EditArtistModal />}</ModalScreenContext.Provider></>)}
tsx// pages/artist/[slug].tsximport { ModalScreenContext } from 'context/modal-screen'import { useRouter } from 'next/router'export default function ArtistPage() {const router = useRouter()return (<><ArtistScreen /><ModalScreenContext.Provider value={true}>{!!router?.query?.showsEditModal && <EditArtistModal />}</ModalScreenContext.Provider></>)}
Notice that the EditArtistModal is wrapped with the ModalScreenContext.Provider, and the value is true.
This means that any component inside of EditArtistModal will know it is a modal, whereas every component inside of ArtistScreen will know it is not a modal.
Use the context​
If you stick to the pattern of always including the word modal in the URL, you can use the useRouter hook to check if the URL contains the query param:
The logic for useIsFocused should now be this: your hook is focused if one of these conditions is true:
the hook is inside of a (mounted) modal, or
the hook is not a modal, and there is no modal mounted
a. Why? If this hook is not in a modal, but a modal is mounted, then that means that this hook is underneath the modal, and thus not focused.
tsimport {useContext } from 'react'import {useRouter } from 'next/router'import {ModalScreenContext } from './context/modal-screen'Âexport functionuseIsFocused () {const {query } =useRouter ()constiAmAModal =useContext (ModalScreenContext )Âif (iAmAModal ) {return true}ÂconstisThereAModalVisibleOnTopOfMe =// check if there is a query param with "modal"Object .keys (query ?? {}).some ((key ) =>key .toLowerCase ().includes ('modal'))Âreturn !isThereAModalVisibleOnTopOfMe }
tsimport {useContext } from 'react'import {useRouter } from 'next/router'import {ModalScreenContext } from './context/modal-screen'Âexport functionuseIsFocused () {const {query } =useRouter ()constiAmAModal =useContext (ModalScreenContext )Âif (iAmAModal ) {return true}ÂconstisThereAModalVisibleOnTopOfMe =// check if there is a query param with "modal"Object .keys (query ?? {}).some ((key ) =>key .toLowerCase ().includes ('modal'))Âreturn !isThereAModalVisibleOnTopOfMe }
To use this as a repeatable method, it's important that you always use the word modal as a query param to denote that a modal is open.
Finally, you can navigate to this modal screen like so:
tsx<Link href="/artists/drake" query={{ showsEditModal: true }} />
tsx<Link href="/artists/drake" query={{ showsEditModal: true }} />
And if you implement some custom modal logic, you might end up having a link with a fancier as prop:
tsx<Link href="/artists/drake" as="/@drake/edit" query={{ showsEditModal: true }} shallow />
tsx<Link href="/artists/drake" as="/@drake/edit" query={{ showsEditModal: true }} shallow />
That way, you could put the edit modal as a full page when someone refreshes. But that's for another day...