skip to content

Focus & Mount Lifecycle

A stack keeps earlier screens mounted, so focus, blur and beforeRemove events replace mount effects. Interviewers probe stale data on return and blocking exit with unsaved edits.

part ofReact Nativeoverview, primer and where to startread it →
on this pageshow

explore

questions

4

In a React Navigation 7 stack, what happens to the product list screen when you push a details screen, and when does it unmount?

level: juniorimportance: must knowfreq 70%

answer

  1. pushing does not unmount
  2. blur, not unmount
  3. removed from state means unmounted
  4. tabs mount on first visit
  5. freezeOnBlur for inactive screens

basics

~20 s

Pushing a details screen keeps the product list mounted underneath with its state intact; it only receives a blur event. It unmounts when its route is removed from the stack state: going back past it, replace or reset.

solid answer

~40 s

A React Navigation 7 stack renders every route in its state, so pushing `ProductDetails` keeps `ProductList` mounted underneath: its component state, scroll position and subscriptions survive, and it simply receives a `blur` event while `ProductDetails` receives `focus`. When the user goes back, `ProductDetails` is removed from the state and unmounts, and `ProductList` gets `focus` again without re-mounting, so its mount-only `useEffect` does not run a second time. A screen unmounts only when its route leaves the navigator's state: `goBack`, `pop` or `popTo` past it, `replace`, or `reset`. Tab and drawer screens follow the same rule; JS bottom tabs render a tab on first visit because `lazy` defaults to `true`, then keep it mounted. Unlike a typical web router, leaving a screen forward does not tear it down.

go deeper

for a junior

Recall that a stack keeps earlier screens mounted and only blurs them, and that a screen unmounts when its route is removed, typically by going back.

for a middle

Explain which actions remove a route, why a mount-only effect does not rerun on return, and how tabs mount lazily and then stay mounted.

for a senior

Show how you stop hidden screens from polling, re-rendering or leaking work, using focus-scoped effects and freezeOnBlur rather than forced remounts.

for a principal

Weigh preserved screen state against memory and background work in deep navigation hierarchies, and set conventions for which screens may hold live resources while unfocused.

## Mounted is not the same as visible In **React Navigation 7**, a navigator renders the screens that are in its **navigation state**, not only the one on top. For a **stack navigator** that means every route in the history is a live React component tree. The route on top is **focused**; the ones underneath are mounted but **unfocused**. Take a shop app with `ProductList → ProductDetails`: 1. The user taps a product and the list calls `navigation.navigate('ProductDetails', { productId })`. 2. `ProductDetails` mounts and receives a **`focus`** event. 3. `ProductList` stays mounted and receives a **`blur`** event. Its `useState` values, its scroll position and any subscriptions it opened are all still there. 4. The user goes back. `ProductDetails` is removed from the state and **unmounts**; `ProductList` receives `focus` again. The practical consequence interviewers look for: a `useEffect(() => { … }, [])` in `ProductList` ran once when the list first mounted and does **not** run again when the user returns, because the component never unmounted. ## When a screen actually unmounts A screen's component unmounts when its **route leaves the navigator's state**. The actions that do that: - `goBack()` or `pop()` on the focused screen; - `popTo()` or `popToTop()` returning to a screen below it; - `replace()`, which swaps the current route for a new one; - `reset()`, which installs a whole new state; - the navigator itself unmounting, for example when a parent screen is removed. Pushing another screen, switching tabs, opening a modal screen on top or the app moving to the background removes nothing, so none of them unmounts the screen. ## The events a screen sees Because mounting no longer tells a screen whether it is visible, React Navigation emits navigation events on the screen's `navigation` object, which a screen can subscribe to with `navigation.addListener`: - **`focus`** when the screen becomes the focused route; - **`blur`** when another route takes focus, while this one stays mounted; - **`beforeRemove`** just before an action removes the route, with the pending action attached, so an edit screen can stop the user leaving with unsaved input. `addListener` returns an unsubscribe function, so a listener added inside `useEffect` is removed by returning that function from the effect. ## Tabs and drawers Tab and drawer navigators keep a route per tab, so the same rule applies. In the JavaScript bottom tab navigator, `lazy` defaults to `true`: a tab renders the first time it is visited rather than at start-up, and after that it **stays mounted** while the user switches between tabs. A cart tab that loaded its contents on mount will therefore show stale data when the user comes back to it later, which is why focus-based effects exist. | Navigator | When a screen first mounts | When it unmounts | |---|---|---| | Stack | when its route is pushed | when its route is removed from the stack | | Bottom tabs | on first visit (`lazy: true` by default) | when the tab navigator unmounts | | Drawer | on first visit | when the drawer navigator unmounts | ## Why the design keeps screens alive Keeping screens mounted is what makes back navigation feel native: the previous screen reappears instantly, at the same scroll offset, with the text the user had typed, instead of re-fetching and re-rendering from scratch. React Navigation's native stack is built on the platform's own screen containers through `react-native-screens`, so the previous screen is also kept by the platform's navigation container. The cost is that unfocused screens still exist: - their effects, timers and subscriptions keep running unless something stops them on blur; - a state change in a store they read makes them re-render even though nobody sees them; - deep stacks of heavy screens hold memory. ## Controlling the cost The tools for unfocused screens are focus-aware rather than mount-aware: 1. **`useFocusEffect`** runs an effect when the screen gains focus and cleans it up when it loses focus, so a polling timer or a location subscription runs only while the screen is visible. 2. **`useIsFocused`** returns whether the screen is focused and re-renders when that changes, for rendering something only while visible, such as a camera preview. 3. **`freezeOnBlur`**, an option on the native stack and bottom tabs, suspends re-rendering of inactive screens through `react-native-screens`. It defaults to `false`, or to `true` when the app calls `enableFreeze()` at start-up. What you should not do is fight the model by forcing remounts, for example by changing a `key` on every focus: that throws away the state users expect back navigation to preserve.

  • The product list polls prices every five seconds with setInterval in a mount effect; what happens after the user opens a product?
    The list stays mounted, so the interval keeps polling while it is hidden under the details screen, spending network and battery and re-rendering an invisible list. Move the timer into `useFocusEffect` and clear it in the cleanup, which runs on blur, so polling stops when the list is covered and resumes when it is focused again.
  • Does opening a modal-presented screen over the list blur the list?
    Yes. A modal presentation is still a new route on top of the stack, so focus moves to it and the list receives `blur`, while remaining mounted underneath. When the modal is dismissed, its route is removed and the list receives `focus` again.

A stack is like browser tabs you open from a link rather than a single page you overwrite: the earlier tab keeps its scroll position and form input while you read the new one, and it only goes away when you close it.

saying these in an interview costs you the question

  • Pushing a new screen unmounts the previous one to save memory.
  • Returning to a screen re-runs its mount-only useEffect.
  • Switching tabs unmounts the tab you leave.
  • Every tab screen renders at app start-up by default.
  • Changing a key on each focus is the right way to refresh a screen.
open as a page

In React Navigation 7 bottom tabs, why does a mount useEffect show a stale cart on returning to the tab, and what fixes it?

level: middleimportance: must knowfreq 66%

basics

~20 s

Visited tabs stay mounted, so a useEffect with empty dependencies runs once and never on return. useFocusEffect runs its callback each time the screen gains focus and its cleanup on blur, so the cart refreshes on every return.

open as a page

In React Navigation 7, when should a screen use useIsFocused rather than useFocusEffect or navigation.isFocused()?

level: middleimportance: should knowfreq 35%

basics

~20 s

Use 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.

open as a page

In React Navigation 7, how do you stop a user leaving a product-review screen with unsaved text, and what can still bypass that guard?

level: seniorimportance: should knowfreq 45%

basics

~10 s

Call usePreventRemove(hasUnsavedText, ({ data }) => confirm, then navigation.dispatch(data.action)). It intercepts any navigation action that would remove the screen, but not switching tabs, pushing another screen, backgrounding or killing the app.

open as a page