In React Navigation 7, when should a screen use useIsFocused rather than useFocusEffect or navigation.isFocused()?
answer
- render versus side effect
- re-renders on focus change
- isFocused() does not re-render
- camera preview only while visible
- cost: two extra renders
basics
~20 sUse useIsFocused when what the screen renders depends on focus, such as mounting a camera preview only while visible; it re-renders on each focus change. Use useFocusEffect for side effects, and never read navigation.isFocused() during render.
solid answer
~40 s`useIsFocused()` returns a boolean and **re-renders** the component whenever the screen gains or loses focus, so it belongs where the rendered output depends on focus: mounting a scanner's camera preview only while the Scan tab is visible, pausing a video element, or showing a different header state. `useFocusEffect` is for **side effects** such as fetching or subscribing, with a cleanup on blur, and causes no render by itself. `navigation.isFocused()` returns the current value but does not subscribe, so calling it in render gives a value that goes stale; it suits event handlers. Because every focus change re-renders a component that uses `useIsFocused`, put it in the smallest component that needs it rather than at the top of a heavy screen.
go deeper
Recall the split: useIsFocused for what you render, useFocusEffect for what you do, navigation.isFocused() only inside handlers.
Explain that useIsFocused subscribes and re-renders on focus changes, while navigation.isFocused() is a one-off read that goes stale in render.
Show you release device resources such as a camera on blur and keep useIsFocused in small components so focus changes do not re-render whole screens.
Set team conventions for focus-dependent resources and rendering so hidden screens neither hold hardware nor burn render time in long-lived tab apps.
## Three ways to ask whether a screen is focused **React Navigation 7** offers three APIs that all answer the question "is this screen focused?", and interviewers use them to check whether a candidate separates rendering from side effects. | API | What it gives you | Re-renders on focus change | Typical use | |---|---|---|---| | `useIsFocused()` | a boolean for the current render | yes | render something only while visible | | `useFocusEffect(cb)` | runs `cb` on focus, its cleanup on blur | no | fetch, subscribe, start timers | | `navigation.isFocused()` | the value at the moment of the call | no | inside an event handler | All three read the same underlying state: the route is focused when it is the focused route of its navigator and every parent navigator up to the container. ## useIsFocused: when output depends on focus `useIsFocused()` subscribes to the screen's `focus` and `blur` events (or to a focus context when the screen is rendered through a `NavigationProvider`) and returns `true` or `false`. When the value changes, the component re-renders. The canonical use is a resource that should exist only while the screen is on show. On a shop app's `Scan` tab, a barcode scanner's camera preview should not keep the camera running after the user switches to `Cart`, because tabs stay mounted after their first visit: ```tsx import type { ComponentType } from 'react'; import { useIsFocused } from '@react-navigation/native'; import { Text, View } from 'react-native'; export function ScanTab({ Preview }: { Preview: ComponentType }) { const isFocused = useIsFocused(); return <View style={{ flex: 1 }}>{isFocused ? <Preview /> : <Text>Paused</Text>}</View>; } ``` Unmounting the preview when the tab blurs releases the camera; mounting it again on focus restarts it. Other examples: - pausing a video or an animation that is expensive to keep running; - switching a status bar or header appearance for the visible screen only; - deferring an expensive subtree until the screen is actually visible. ## How focus is decided A screen is focused only when it is the focused route of its own navigator **and** its parent screen is focused too, all the way up to the container. `navigation.isFocused()` implements exactly that walk: it compares the navigator's focused route key with the screen's key and then asks the parent. The practical effect is that a screen inside a stack that sits inside a tab is unfocused whenever its tab is not selected, even though it is still on top of its own stack. `useIsFocused()` keeps that value current by subscribing through React's `useSyncExternalStore` to the screen's focus and blur events. ## useFocusEffect: when work depends on focus If the goal is to **do** something rather than **show** something, `useFocusEffect` is the better tool. It runs a memoised callback when the screen gains focus and its cleanup when it loses focus, without re-rendering anything. Implementing a refetch with `useIsFocused` plus `useEffect(…, [isFocused])` works, but costs an extra render on every focus change and spreads one concern across two hooks. ## navigation.isFocused(): only outside render `navigation.isFocused()` is a method, not a hook. It returns the focus state at the moment it is called and does not subscribe, so a component that calls it during render keeps showing whatever value it saw last until something else re-renders it. The type definitions warn against using it in render. It is the right tool in callbacks: - a push-notification handler deciding whether to show an in-app banner or to navigate; - a timer callback checking whether the screen is still visible before updating it; - an event listener that should ignore events while the screen is hidden. ## Performance considerations Every component that calls `useIsFocused()` re-renders on **each** focus and blur. Placed at the top of a large screen, that re-renders the whole screen twice for a round trip to another tab. Keep the hook in the smallest component whose output depends on it, as the `ScanTab` wrapper above does, and pass the boolean down only where needed. For suspending re-renders of whole inactive screens, the navigator option `freezeOnBlur` is the dedicated mechanism. **Common mistakes:** 1. Using `useIsFocused` purely to trigger a fetch, when `useFocusEffect` would do it without extra renders. 2. Reading `navigation.isFocused()` in JSX and wondering why the UI does not update. 3. Forgetting that focus covers navigation only: an app returning from the background does not change it.
- Why is useIsFocused plus useEffect keyed on isFocused a weaker way to refetch on focus?It works, but the component first re-renders because the boolean changed and only then runs the effect, so every focus change costs an extra render of that component. `useFocusEffect` runs the same work directly from the focus event and pairs it with a cleanup on blur, in one hook.
- A header badge calls navigation.isFocused() during render and sometimes shows the wrong state; why?`navigation.isFocused()` reads the value once and does not subscribe to focus changes, so nothing re-renders the component when focus moves. The badge keeps its last value until an unrelated render. Use `useIsFocused()` if the output must follow focus.
saying these in an interview costs you the question
- navigation.isFocused() in render updates the UI when focus changes.
- useIsFocused is the best way to trigger a fetch on focus.
- useIsFocused has no rendering cost, so put it at the top of every screen.
- useFocusEffect re-renders the screen on every focus change.