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
ts
export {useIsFocused } from '@react-navigation/native'
ts
export {useIsFocused } from '@react-navigation/native'
hooks/use-is-focused.web.ts
ts
export functionuseIsFocused () {return true}
ts
export functionuseIsFocused () {return true}
On Web, screens are always focused when they're mounted.
Import your file​
ts
import { useIsFocused } from 'hooks/use-is-focused'
ts
import { 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.
ts
import {createContext } from 'react'Âexport constModalScreenContext =createContext (false)
ts
import {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.
ts
import {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 }
ts
import {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...