"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.
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, you can run the command below to create your project:
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
yarn add \
@react-navigation/bottom-tabs \
@react-navigation/native \
@react-navigation/stack
react-navigation
needs some libraries included in our project:
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.
yarn add \
swr \
@nandorojo/swr-react-native@beta \
@react-native-community/netinfo
Finally, let's add axios
to handle your HTTP requests
yarn add axios
Optionally, we can add typescript as development dependency:
yarn add typescript -D
And create tsconfig.json
file with
tsc --init
Step 3: Configure baseUrl:
We can create a folder named services
in the root of our project with three files:
-
api.ts
(orapi.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:
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
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:
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:
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:
import useSWR from 'swr';
import { useSWRNativeRevalidate } from "@nandorojo/swr-react-native";
We need to import our async function from services
folder too:
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:
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:
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.
useSWRNativeRevalidate({ mutate });
Leaving our code like this:
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.
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:
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:
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:
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
Last step: Update the data and check the revalidation!
To see revalidateOnFocus
in action, I updated the last neighborhood name using Postman and when neighborhood screen was in focus again, this was the result: check result gif
Check the repository with the code here
I would like to know your thoughts about this tutorial too, so feel free to comment!
Top comments (0)