Chapter 3: Queries
Full Stack React Native
link Queries
By the end of this lesson, developers will be able to:
- Fetch GraphQL data with the Apollo client
- Structure a GraphQL Query
- Display data from Queries
link The Story So Far
So far, we set up a React Native application and a GraphQL/Express server. The app is designed to fetch random prompts from the server.
In this section we set up our first Apollo client application.
What is Apollo Client?
Apollo Client is a complete state management library for JavaScript apps. Simply write a GraphQL query, and Apollo Client will take care of requesting and caching your data, as well as updating your UI.
Fetching data with Apollo Client guides you to structure your code in a predictable, declarative way consistent with modern React best practices. With Apollo, you can build high-quality features faster without the hassle of writing data plumbing boilerplate.
There are plenty of features to consider with Apollo and here are some of my favorites:
- Declarative data fetching: Write a query and receive data without manually tracking loading states
- Incrementally adoptable: Drop Apollo into any JavaScript app seamlessly
- Designed for modern React: Take advantage of the latest React features, such as hooks
With Apollo we can reduce boilerplate and request data from a client-side application. Let's get started!
App Setup
In case you missed the initial app setup, here are commands to get you up and running:
git clone https://github.com/Maelstroms38/react-native-starter.git
cd react-native-starter
yarn
yarn start
Server Setup
In case you missed the Express server setup, please follow the previous lesson in Chapter 2. Or, run the following commands:
git clone https://github.com/Maelstroms38/express-api
cd express-api
yarn
yarn db:reset
yarn start
Setting Up
Let's start by opening and running both projects in two separate windows.
cd <app-name>
yarn start
cd <server-name>
yarn start
Once you have confirmed both projects are running, we will write our first GraphQL query.
link GraphQL Queries - Apollo Client
The writing prompts app currently displays no prompts. In order to make it a dynamic list, we created a server that sends random prompts.
First, we will install the Apollo
library for our client's network requests.
Heads Up! This lesson's code edits will only affect your React Native project.
Run the following command inside your React Native project.
yarn add @apollo/react-hooks apollo-client apollo-cache-inmemory apollo-link-http graphql graphql-tag
With Apollo installed, we can query the localhost
server for random prompts.
Create a new Prompt.js
component, which we will reference inside App.js
.
// Prompt.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
export default function Prompt() {
return <View></View>
}
Create a new file called ApolloClient.js
and insert the following:
import { ApolloClient } from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { HttpLink } from 'apollo-link-http';
const BASE_URL = 'http://localhost:4000';
const httpLink = new HttpLink({
uri: BASE_URL
})
const client = new ApolloClient({
link: httpLink,
cache: new InMemoryCache()
})
export default client;
Let's modify the React Native app code, with the following code inside App.js
:
Click here for the full `App.js` source code so far.
import React, { useState } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { ApolloProvider } from '@apollo/react-hooks';
import client from './ApolloClient';
import Prompt from './Prompt';
export default function App() {
return (
<ApolloProvider client={client}>
<Prompt />
</ApolloProvider>
);
}
Apollo Client is designed to fetch graph data from any JavaScript frontend. No frameworks needed. However, there are view layer integrations for different frameworks that makes it easier to bind queries to the UI -- such as React hooks.
Now, we're ready to start building our first component with the useQuery hook in the next section.
Query for Random Prompt
The useQuery
hook is one of the most important building blocks of an Apollo app. It's a React Hook that fetches a GraphQL query and exposes the result so you can render your UI based on the data it returns.
With useQuery
imported at the top of our App.js
, we can write a function that fetches a random prompt inside Prompt.js
.
import React, { useState, useEffect } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { useQuery } from '@apollo/react-hooks';
import RoundedButton from './RoundedButton';
import gql from 'graphql-tag';
// Queries
const PROMPT_QUERY = gql`
query {
prompt {
id
title
}
}
`;
Hooking into State
To create a component with useQuery
, wire your component up to use the loading
, data
, and refetch
properties on the result object to render UI in your app.
- Next, we will add a new
useQuery
hook to keep track of theprompt
string's state. - We will also modify the
RoundedButton
'sonPress
method to utilize theuseQuery
hook'srefetch
method. This will fetch new data each time the button is pressed.
// App.js
export default function Prompt() {
const [color, setColor] = useState('#161616');
const { loading, data, refetch } = useQuery(PROMPT_QUERY);
return (
<View style={[styles.container, { backgroundColor: color }]}>
{!loading && data && data.prompt &&
<Text style={styles.prompt}>{data.prompt.title}</Text>}
<RoundedButton
text="Next"
textColor="#fff"
onPress={() => {
refetch()
setColor(randomRgb())
}}
/>
</View>
)
}
Click here for the full Prompt.js source code so far.
import React, { useState, useEffect } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { useQuery } from '@apollo/react-hooks';
import RoundedButton from './RoundedButton';
import gql from 'graphql-tag';
// Queries
const PROMPT_QUERY = gql`
query {
prompt {
id
title
}
}
`;
export default function Prompt() {
const [color, setColor] = useState('#161616');
const { loading, data, refetch } = useQuery(PROMPT_QUERY);
return (
<View style={[styles.container, { backgroundColor: color }]}>
{!loading && data && data.prompt &&
<Text style={styles.prompt}>{data.prompt.title}</Text>}
<RoundedButton
text="Next"
textColor="#fff"
onPress={() => {
refetch()
setColor(randomRgb())
}}
/>
</View>
)
}
const randomRgb = () => {
const red = Math.floor(Math.random() * 256);
const green = Math.floor(Math.random() * 256);
const blue = Math.floor(Math.random() * 256);
return `rgb(${red}, ${green}, ${blue})`;
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
padding: 20
},
prompt: {
color: 'white',
fontSize: 22,
padding: 20,
textAlign: 'center'
}
});
link Display Initial Prompt
Right now, we see a new prompt each time the user taps "Next". This is great, but our initial prompt is empty.
How can we remedy this using Hooks?
Given the new hooks API, we can call a method called useEffect
, which functions like the componentDidMount
and componentDidUpdate
lifecycle methods. Let's try it out!
Using useEffect
export default function Prompt() {
const [color, setColor] = useState('#161616');
const { loading, data, refetch } = useQuery(PROMPT_QUERY);
// the "useEffect" hook runs on first render.
useEffect(() => {
refetch()
setColor(randomRgb())
}, []);
// ^^ Don't forget this empty array!
/* ... */
}
Using useEffect
will update our initial state to refetch
a random prompt. This displays the initial prompt and background color upon first render.
WELL DONE!
And with that, we are ready to wrap up this lesson.
link Bonus Challenge
Share Prompts
The app currently displays a unique prompt each time the user presses "Next".
Try adding a second button to Share the current prompt.
Wrapping Up
Today we made our first React Native GraphQL app! The next section introduces a new bitcoin tracking application.