Component Lifecycles with React Navigation in React Native
Tags: reactnative, reactnavigation
Published: 2021-07-17 13:42:50

---
title: Component Lifecycles with React Navigation in React Native
published: true
date: 2021-07-17 00:00:00 UTC
tags: [reactnative, reactnavigation]
description: How to refresh an API call when a user navigates back in a stack
canonical_url: https://bionicjulia.com/blog/component-lifecycles-with-react-navigation-in-react-native
---

Here's another "gotcha" I came across this week as I continue to familiarise myself with React Native. Check out my previous post [Transitioning from React to React Native](https://bionicjulia.com/blog/transitioning-from-react-to-react-native) if you're like me, and making the move from React to React Native.

### Lifecycles in React Native and React Navigation

The mobile app I'm working on uses React Navigation and stack navigators. For the purposes of illustration, let's say we have 2 React components that act as pages / screens (depending if you're coming at it from the angle of web or mobile development). The first component will be called `Home` and the second, `Details`.

Come from React for web development, if I navigated from `Home` to the `Details` page,
I would expect the `Home` component to unmount, and the `Details` component to mount. If I navigate back, I'd expect the `Home` component to mount again at that point.

This expected component lifecycle does not behave in the same way when using stack navigation in React Native. What happens instead is as you navigate from `Home` to `Details`, `Home` **does not unmount** as it remains part of the stack, even as the `Details` component mounts. When you navigate back in the stack to `Home`, as the component was never unmounted, it just come back into **focus**. Note however, that at this point, the `Details` component **does unmount**, since it is no longer part of the stack. Check out the [documentation](https://reactnavigation.org/docs/navigation-lifecycle) if you'd like more information.

### React Native screen events

The specific situation I came across was how to then refresh an API call, when a user navigates back to a previous screen that remains part of the stack. I'd normally just stick an API call within the `useEffect` hook and rely on this to be called upon the component mounting, but this clearly doesn't work with mobile stack navigation due to the difference in lifecycle for React Native.

Turns out there are two ways to do this, both of which relies on the concept of a screen being in focus. React Native emits screen events, whereby if a user navigates to a screen, the screen is said to be in **focus**. (As an aside, if a user navigates away from a screen, that screen is now in **blur**.) We can thus listen to these events and create our desired side effects.

**Method 1: Set up a manual listener**

In my example, I want to make an API call whenever a particular screen component is in focus. I can do this by setting up a manual listener. This sits within React's `useEffect` hook. The sequence of events is therefore:

- The component mounts.
- We set up a `focus` listener. As the screen is currently in focus, it makes an immediate API call.
- We navigate to another screen. This first screen is now out of focus, but still mounted. The `useEffect` hook, and thus the `focus` listener is still in play.
- We navigate back to this first screen, which means it's now in focus again. The API call is made once again.

Borrowing the example from the official docs:

```jsx
function Profile({ navigation }) {
  React.useEffect(() => {
    const unsubscribe = navigation.addListener('focus', () => {
      // Make API call here
    })

    return unsubscribe
  }, [navigation])

  return <ProfileContent />
}
```

Note that whenever you add a listener, you should explicitly ensure it's cleaned up upon the component unmounting. This is done with `return unsubscribe` in the example above.

**Method 2: Use the useFocusEffect hook**

Instead of manually adding a listener, we can use the `useFocusEffect` hook that's provided by React Navigation. This is similar to React's `useEffect` hook but runs on a screen being in focus instead.

In my case, I wanted to make an asynchronous API call. Here's how you can set the hook up for async functions. Expanding the example from the docs:

```jsx
import { useFocusEffect } from '@react-navigation/native'

function Profile() {
  useFocusEffect(
    React.useCallback(() => {
      let isActive = true

      const fetchList = async () => {
        try {
          const tests = (await listApiService.list()).data

          if (isActive) {
            setList(test)
          }
        } catch (_) {
          setError('Something went wrong')
        }
      }

      fetchList()

      return () => {
        isActive = false
      }
    }, []),
  )

  return <ProfileContent />
}
```

Note that you want to wrap your side effect up in a `useCallback` function to ensure that your API doesn't get called unnecessarily.

### Conclusion

The official docs recommends going with method 2 wherever possible. It's cleaner and is designed to integrate with React Native's component lifecycle, in addition to how React Navigation works. I also prefer the way it's written, and think it looks a lot cleaner. 🧼

Let me know what you think! Talk to me on [Instagram](https://instagram.com/bionicjulia) or [Twitter](https://twitter.com/bionicjulia)!