How to revalidate data on focus with SWR and React Native
Tags: reactnative, swr
Published: 2021-11-13 18:37:43

"With SWR, components will get a stream of data updates constantly and automatically. And the UI will be always fast and reactive." - SWR Documentation

But some main features like `revalidateOnFocus` or `revalidateOnReconnect` are not supported by default when developing with React Native, and [this issue was already reported](https://github.com/vercel/swr/issues/417).

From this issue, the package `swr-react-native` was created to help us!

In this tutorial I will show how to revalidate data when a screen is focused again.

__Step 1: Create the project__
After following the official React Native tutorial to [set up the development environment](https://reactnative.dev/docs/environment-setup), you can run the command below to create your project:

```sh
npx react-native init swr-rn-revalidateOnFocus
                    # or whatever name you like
```

__Step 2: Install dependencies__
After that, we can add the dependencies that we need:
React navigation to handle navigation between screens

```sh
yarn add \
@react-navigation/bottom-tabs \
@react-navigation/native \
@react-navigation/stack
```

`react-navigation` needs some libraries included in our project:

```sh
yarn add \
react-native-gesture-handler \
react-native-safe-area-context \
react-native-screens
```

Next, let's install `swr` and `swr-react-native` with `netinfo` dependency.

```sh
yarn add \
swr \
@nandorojo/swr-react-native@beta \
@react-native-community/netinfo
```

Finally, let's add `axios` to handle your HTTP requests

```sh
yarn add axios
```

Optionally, we can add typescript as development dependency:

```sh
yarn add typescript -D
```

And create `tsconfig.json` file with

```sh
tsc --init 
```

__Step 3: Configure baseUrl__:
We can create a folder named `services` in the root of our project with three files:
- `api.ts` (or `api.js` if you don't installed typescript)
- `cities.ts` (one entity where we're gonna request data)
- `neighborhood.ts` (another entity where we're gonna request data)

In `api` file we're gonna use `axios` to indicate which url we'll use to request data:
```javascript
import axios from 'axios';

const api = axios.create({
  baseURL: 'YOUR_BASE_URL'
})

export default api;
```

On both remaining files let's write async functions that will make GET HTTP requests:

`neighborhoods.ts`

```javascript
import api from './api';
const endpoint = 'YOUR_ENDPOINT'

async function getNeighborhoods(){
  const response = await api.get(endpoint)
  return response.data
}

export {
  getNeighborhoods
}
```

You can write almost the same code in `cities.ts` file, just change the function name and the value of `endpoint` variable.

__Step 4: Create screens__
In our root project let's create `pages` folder with `cities` and `neighborhoods` folders inside it and those will contain files for css style, tsx code e one file to export our screen:

![folder-structure](https://i.ibb.co/ZJB6XFc/folder-structure.png)

You can edit the `.tsx` and `.css.ts` files to style the screen the way you want and `index.ts` just to import and export our screen, like that:

```javascript
import Neighborhoods from './Neighborhoods'
export default Neighborhoods;
```

However, let's focus on the part that we use swr on `Neighborhoods.tsx` file.

Import `swr` and `swr-react-native` hooks:

```javascript
import useSWR from 'swr';
import { useSWRNativeRevalidate } from "@nandorojo/swr-react-native";
```

We need to import our async function from `services` folder too:

```javascript
import { getNeighborhoods } from '../../services/neighborhoods';
```

Inside our component function, let's create the `fetcher` variable that we'll pass as parameter to `useSWR` hook later:

```javascript
const fetcher = () => getNeighborhoods().then(data => data);
```

Basically, that variable is calling the asynchronous function and returning the data requested.

Now, let's understand the `useSWR` hook:

```javascript
const { data: neighborhoods, mutate } = useSWR('your_endpoint', fetcher);
```

That hook needs two parameters, the first one is a unique key for the request and in many cases the value will be the endpoint. The second one is a `Promise` to get our data, here we will pass the `fetcher` variable created previously.

Finally, let's include `swr-react-native` hook to handle revalidation and take advantage of `revalidateOnFocus` feature.

```javascript
useSWRNativeRevalidate({ mutate });
```

Leaving our code like this:
```javascript
export default function Neighborhoods(){
 const fetcher = () => getNeighborhoods().then(data => data)
 const { data: neighborhoods, mutate } = useSWR('/v1/neighborhood', fetcher)
 useSWRNativeRevalidate({ mutate });
 return (
  // ...
 )
}
```

__Step 5: Create navigators__
In this step we'll create stack and tabs navigators. So let's begin with the tabs one:
First, create a folder in the project root named `routes` and inside it create `Tabs.tsx` file. We'll define which screen will be shown when a tab is pressed.

```javascript
import React from 'react';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

// Screens
import Cities from '../pages/cities';
import Neighborhoods from '../pages/neighborhoods';

const { Navigator, Screen } = createBottomTabNavigator();

export default function Tabs() {
 return (
  <Navigator screenOptions={{ headerShown: false }}>
   <Screen
    name="cities"
    component={Cities}
   />
   <Screen
    name="neighborhoods"
    component={Neighborhoods}
   />
  </Navigator>
 )
}
```

Create a `Stack.tsx` file in the same folder where we'll just indicate the `Tabs` component as screen:

```javascript
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import Tabs from './Tabs';

const { Navigator, Screen } = createStackNavigator();

export default function Stack(){
 return(
  <NavigationContainer>
   <Navigator
    screenOptions={{ headerShown: false }}
    initialRouteName="tabs"
   >
    <Screen name="tabs" component={Tabs} />
   </Navigator>
  </NavigationContainer>
 )
}
```

__Step 6: Importing stack navigator__
From here, we already have our navigation done. But to use it we need to import the Stack component in `App.tsx` (or `App.js`) and configure some swr global parameters:

```javascript
import React from 'react';
import Stack from './routes/Stack';
import { SWRConfig } from 'swr'

export default function App() {
 return (
  <SWRConfig
   // these will be passed as third parameter
   // of every useSWR hook used in our project
   value={{
    revalidateOnFocus: true,
    revalidateOnReconnect: true,
    revalidateIfStale: true,
    focusThrottleInterval: 5000
   }}
  >
   <Stack />
  </SWRConfig>
 );
};
```

__Step 7: Show the data__
Going back to our `Neighborhoods.tsx` file, in the return we can map over the `neighborhood` variable:

```javascript
import React from 'react';
import { useSWRNativeRevalidate } from '@nandorojo/swr-react-native';
import { ActivityIndicator, Text, View } from 'react-native';
import useSWR from 'swr';
import { getNeighborhoods } from '../../services/neighborhoods';
import styles from './Neighborhoods.css';

export default function Neighborhoods(){
 const fetcher = () => getNeighborhoods().then(data => data)
 const { data: neighborhoods, mutate } = useSWR('/v1/neighborhood', fetcher)
 useSWRNativeRevalidate({ mutate });

 return(
  <View style={styles.container}>
   {
    !neighborhoods ? <ActivityIndicator animating={true} size={'large'} /> :
    neighborhoods.map((neighborhood: any) => (
     <View key={neighborhood._id}>
      <Text style={styles.name}>
       {neighborhood.name}
      </Text>
      <Text style={styles.city}>
       {neighborhood.city.name}
      </Text>
     </View>
    ))
   }
  </View>
 )
}
```

In the example above I'm showing the neighborhood name and the city name associated with it: [check screenshot](https://i.ibb.co/FB4P7FQ/nbhds-screen.jpg)

__Last step: Update the data and check the revalidation!__
To see `revalidateOnFocus` in action, I updated the last neighborhood name using [Postman](https://www.postman.com/) and when neighborhood screen was in focus again, this was the result: [check result gif](https://i.ibb.co/pRVXJWN/swr-revalidate-on-focus.gif)

Check the repository with the code [here](https://github.com/anabeatrizzz/swr-and-rn)
I would like to know your thoughts about this tutorial too, so feel free to comment!