React Native Tutorial: Getting to Know React Query
Data retrieval from a remote source is required in almost every program you will create. Unfortunately, retrieving data is rarely as straightforward as simply retrieving it and presenting it. Consider the following:
What should we do while we wait for the data to load?
What if something goes wrong?
How do I keep my data current?
What if my user’s internet connection is weak or slow?
React Query can assist you with all of these tasks.
Today, we’ll show a simple showcase app from the fetch API to React Query.
1. App.js
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { QueryClient, QueryClientProvider } from 'react-query';
import { MoviesListScreen } from './screens/MoviesListScreen';
import { MovieDetailsScreen } from './screens/MovieDetailsScreen';
const Stack = createStackNavigator();
const queryClient = new QueryClient({
defaultOptions: { queries: { retry: 2 } },
});
function MoviesStack() {
return (
<Stack.Navigator initialRouteName="MoviesList">
<Stack.Screen
name="MoviesList"
component={MoviesListScreen}
options={{
headerTitle: 'Movies',
}}
/>
<Stack.Screen
name="MovieDetails"
component={MovieDetailsScreen}
options={{
headerTitle: 'Movie details',
}}
/>
</Stack.Navigator>
);
}
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<NavigationContainer>
<MoviesStack />
</NavigationContainer>
</QueryClientProvider>
);
}
2. MoviesListScreen.js
import * as React from 'react';
import { FlatList, RefreshControl } from 'react-native';
import { useQuery } from 'react-query';
import { LoadingIndicator } from '../components/LoadingIndicator';
import { ErrorMessage } from '../components/ErrorMessage';
import { Divider } from '../components/Divider';
import { ListItem } from '../components/ListItem';
import { useRefreshByUser } from '../hooks/useRefreshByUser';
import { useRefreshOnFocus } from '../hooks/useRefreshOnFocus';
import { fetchMovies } from '../lib/api';
export function MoviesListScreen({ navigation }) {
const { isLoading, error, data, refetch } = useQuery(['movies'], fetchMovies);
const { isRefetchingByUser, refetchByUser } = useRefreshByUser(refetch);
useRefreshOnFocus(refetch);
const onListItemPress = React.useCallback(
(movie) => {
navigation.navigate('MovieDetails', {
movie,
});
},
[navigation]
);
const renderItem = React.useCallback(
({ item }) => {
return <ListItem item={item} onPress={onListItemPress} />;
},
[onListItemPress]
);
if (isLoading) return <LoadingIndicator />;
if (error) return <ErrorMessage message={error.message}></ErrorMessage>;
return (
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={(item) => item.title}
ItemSeparatorComponent={() => <Divider />}
refreshControl={
<RefreshControl
refreshing={isRefetchingByUser}
onRefresh={refetchByUser}
/>
}></FlatList>
);
}
3. MovieDetailsScreen.js
import * as React from 'react';
import { View, RefreshControl, StyleSheet, ScrollView } from 'react-native';
import { Title, Paragraph } from 'react-native-paper';
import { useQuery } from 'react-query';
import { LoadingIndicator } from '../components/LoadingIndicator';
import { ErrorMessage } from '../components/ErrorMessage';
import { useRefreshByUser } from '../hooks/useRefreshByUser';
import { fetchMovie } from '../lib/api';
export function MovieDetailsScreen({ route }) {
const { isLoading, error, data, refetch } = useQuery(
['movie', route.params.movie.title],
() => fetchMovie(route.params.movie.title),
{ initialData: route.params.movie }
);
const { isRefetchingByUser, refetchByUser } = useRefreshByUser(refetch);
if (isLoading) return <LoadingIndicator />;
if (error) return <ErrorMessage message={error.message}></ErrorMessage>;
return (
<ScrollView
refreshControl={
<RefreshControl
refreshing={isRefetchingByUser}
onRefresh={refetchByUser}
/>
}>
<View style={styles.titleRow}>
<Title>
{data.title} ({data.year})
</Title>
</View>
{data.info ? (
<>
<View style={styles.infoRow}>
<Paragraph>{data.info.plot}</Paragraph>
</View>
<View style={styles.actorsRow}>
<Paragraph>
{data.info.actors.slice(0, -1).join(', ') +
' or ' +
data.info.actors.slice(-1)}
</Paragraph>
</View>
</>
) : (
<LoadingIndicator />
)}
</ScrollView>
);
}
const styles = StyleSheet.create({
titleRow: {
flexDirection: 'row',
margin: 20,
},
infoRow: {
flexDirection: 'row',
margin: 20,
},
actorsRow: {
flexDirection: 'column',
margin: 20,
marginTop: 10,
},
});
Note: The code showing above only the main part, please check the sample code on snack for more detail code
Snack Link : https://snack.expo.dev/@rudiahmad/react-query-simple-example