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

Builder Book

Source

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.

Source

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 the prompt string's state.
  • We will also modify the RoundedButton's onPress method to utilize the useQuery hook's refetch 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.

format_list_bulleted
help_outline