Navigate back to the homepage

Getting started with React & Apollo Client

Ezekiel Ekunola
September 30th, 2019 · 2 min read

What is Apollo Client

Apollo Client is a complete state management library for JavaScript apps. It makes use of a GraphQL API to handle data fetching. What this means is in order to make use of Apollo Client, you need to have a GraphQL API that you would connect to.

What is GraphQL

GraphQL is an open-source data query and manipulation language for APIs, and a runtime for fulfilling queries with existing data. GraphQL makes use of Mutation and Query to achieve this.

What is a Query and Mutation

  • Query: A GraphQL query is used to read or fetch data. A sample GraphQL query is shown in the example below.
1{
2 query getUserDetails {
3 users {
4 id
5 name
6 email
7 }
8 }
9}

Note: The above query is named getUserDetails and it gets back the id, name and email fields.

  • Mutation: Mutations are used for any type of request that changes the data, creating, updating and deleting operations. A sample GraphQL mutation looks like the example shown below.
1{
2 mutation addUser(name: String!, email: String!){
3 addUser(name: $name, email: $email){
4 id
5 name
6 email
7 created_at
8 }
9 }
10}

Note: In the mutation example above, it receives name and email as parameters and gets back the id, name, email and created_at fields as response.

Setup React Application

I’ll be using create-react-app boilerplate to setup my react application. On your terminal run the command below to generate a react boilerplate

1npx create-react-app rick-and-morty

after the above command completes, open the generated folder in your Integrated Development Environment.

Install Dependencies

1npm install apollo-boost graphql react-apollo

Connect Client

To connect the react application to the Graphql API, in the index.js file of your react application, add the following code below.

1import ApolloClient from 'apollo-boost';
2import { ApolloProvider } from 'react-apollo';
3
4const client = new ApolloClient({
5 uri: 'https://rickandmortyapi.com/graphql/' //URL of the GraphQL server
6});

…then wrap your sub-components with the ApolloProvider, passing in the client we defined above as prop. An example is shown below.

1ReactDOM.render(
2 <ApolloProvider client={client}>
3 <App />
4 </ApolloProvider>,
5 document.getElementById('root')
6);

Once the above is done, we have successfully setup a basic apollo client connection to the backend GraphQL API. Note: Find more here, for more advanced Apollo client setup and configurations.

There are different methods of consuming a Graphql API when using Apollo Client, they are:

  • Render Props
  • Hooks
  • Higher-Order Component (HOC)

All the different methods of consuming a GraphQL API can be done with the use of the react-apollo package we installed earlier.

Queries

Render Props

To make queries with the Render Prop method, we need to use the Query component from react-apollo. An example is shown below.

1import React from 'react';
2import { Query } from 'react-apollo';
3import { gql } from 'apollo-boost';
4
5const GET_CHARACTERS = gql`
6 query getCharacters {
7 characters {
8 results {
9 id
10 name
11 image
12 }
13 }
14 }
15`;
16
17export default function CharacterWithRender() {
18 return (
19 <Query query={GET_CHARACTERS}>
20 {({ loading, error, data }) => {
21 if (loading) return 'Loading...';
22 if (error) return `Error! ${error.message}`;
23
24 return (
25 <div className="characters">
26 {data.characters.results.map(character => (
27 <div key={character.name} className="character">
28 <img src={character.image} alt={character.name} />
29 <p>{character.name}</p>
30 </div>
31 ))}
32 </div>
33 );
34 }}
35 </Query>
36 );
37}

Hooks

To make queries with the Hooks method, we need to use the useQuery hook from react-apollo. An example is shown below.

An example is shown below

1import React from 'react';
2import { gql } from 'apollo-boost';
3import { useQuery } from 'react-apollo';
4
5const GET_CHARACTERS = gql`
6 query getCharacters {
7 characters {
8 results {
9 id
10 name
11 image
12 }
13 }
14 }
15`;
16
17function CharacterWithHook() {
18 const { loading, error, data } = useQuery(GET_CHARACTERS);
19 if (error) {
20 return <div>Error</div>;
21 }
22
23 if (loading) {
24 return (
25 <div className="App">
26 <h2>Loading...</h2>
27 </div>
28 );
29 }
30 if (data) {
31 if (data.characters.results.length > 0) {
32 return (
33 <div className="characters">
34 {data.characters.results.map(character => (
35 <div key={character.name} className="character">
36 <img src={character.image} alt={character.name} />
37 <p>{character.name}</p>
38 </div>
39 ))}
40 </div>
41 );
42 }
43 }
44}
45
46export default CharacterWithHook;

Higher Order Component (HOC)

We can also use the withApollo Higher Order Component to make queries, you can do so by simply wrapping your component’s export with withApollo. This injects a client prop into the component, thus enables you to make GraphQL queries. An example is shown below

1import React, { useState } from 'react';
2import { gql } from 'apollo-boost';
3import { withApollo } from 'react-apollo';
4
5const GET_CHARACTERS = gql`
6 query getCharacters {
7 characters {
8 results {
9 id
10 name
11 image
12 }
13 }
14 }
15`;
16
17function CharacterWithHOC({ client }) {
18 const [characters, setCharacters] = useState([]);
19
20 client
21 .query({ query: GET_CHARACTERS })
22 .then(res => setCharacters(res.data.characters.results))
23 .catch(err => console.log(err));
24
25 if (characters.length > 0) {
26 return (
27 <div className="characters">
28 {characters.map(character => (
29 <div key={character.name} className="character">
30 <img src={character.image} alt={character.name} />
31 <p>{character.name}</p>
32 </div>
33 ))}
34 </div>
35 );
36 }
37 return (
38 <div className="App">
39 <h2>Loading...</h2>
40 </div>
41 );
42}
43
44export default withApollo(CharacterWithHOC);

Mutations

Render Props

To make mutations with the Render Prop method, we need to use the Mutation component from react-apollo. An example is shown below.

1import React, { useState } from 'react';
2import { Mutation } from 'react-apollo';
3import { gql } from 'apollo-boost';
4
5const LOGIN_MUTATION = gql`
6 mutation userLogin($email: String!, $password: String!) {
7 userLogin(email: $email, password: $password) {
8 username
9 email
10 id
11 token
12 }
13 }
14`;
15
16export default function MutationWithRender() {
17 const [email, setEmail] = useState('');
18 const [password, setPassword] = useState('');
19
20 return (
21 <Mutation mutation={LOGIN_MUTATION}>
22 {(loginUser, { loading, error, data }) => {
23 if (loading) return 'Loading...';
24 if (error) return `Error! ${error.message}`;
25
26 return (
27 <form
28 id="signinForm"
29 className="text-center p-4"
30 onSubmit={e => {
31 e.preventDefault();
32 loginUser({ variables: { email, password } });
33 }}
34 >
35 <p className="h4 mb-4 f-1">Sign In</p>
36
37 <input
38 title="Email"
39 id="email"
40 name="email"
41 value={email}
42 onChange={e => setEmail(e.target.value)}
43 type="email"
44 required
45 />
46 <input
47 title="Password"
48 id="password"
49 name="password"
50 type="password"
51 value={password}
52 onChange={e => setPassword(e.target.value)}
53 required
54 />
55
56 <div className="form-group my-4">
57 <button className="btn btn-block" type="submit">
58 Sign In
59 </button>
60 </div>
61 </form>
62 );
63 }}
64 </Mutation>
65 );
66}

Hooks

To make mutations with the Hooks method, we need to use the useMutation hook from react-apollo. An example is shown below.

An example is shown below

1import React, { useState } from 'react';
2import { useMutation } from 'react-apollo';
3import { gql } from 'apollo-boost';
4
5const LOGIN_MUTATION = gql`
6 mutation userLogin($email: String!, $password: String!) {
7 userLogin(email: $email, password: $password) {
8 username
9 email
10 id
11 token
12 }
13 }
14`;
15
16export function MutationWithHook() {
17 const [email, setEmail] = useState('');
18 const [password, setPassword] = useState('');
19
20 const [loginUser, { data, error, loading }] = useMutation(LOGIN_MUTATION);
21
22 if (error) {
23 alert('Error Logging In User');
24 }
25
26 if (data) {
27 alert('Successfully Logged In');
28 }
29
30 return (
31 <form
32 id="signinForm"
33 className="text-center p-4"
34 onSubmit={e => {
35 e.preventDefault();
36 loginUser({ variables: { email, password } });
37 }}
38 >
39 <p className="h4 mb-4 f-1">Sign In</p>
40
41 <input
42 title="Email"
43 id="email"
44 name="email"
45 value={email}
46 onChange={e => setEmail(e.target.value)}
47 type="email"
48 required
49 />
50 <input
51 title="Password"
52 id="password"
53 name="password"
54 type="password"
55 value={password}
56 onChange={e => setPassword(e.target.value)}
57 required
58 />
59
60 <div className="form-group my-4">
61 <button className="btn btn-block" type="submit">
62 Sign In
63 </button>
64 </div>
65 </form>
66 );
67}
68
69export default MutationWithHook;

Higher Order Component (HOC)

We can also use the withApollo Higher Order Component to make mutations, you can do so by simply wrapping your component’s export with withApollo. This injects a client prop into the component, thus enables you to make GraphQL mutations.

An example is shown below

1import React, { useState } from 'react';
2import { withApollo } from 'react-apollo';
3import { gql } from 'apollo-boost';
4
5const LOGIN_MUTATION = gql`
6 mutation userLogin($email: String!, $password: String!) {
7 userLogin(email: $email, password: $password) {
8 username
9 email
10 id
11 token
12 }
13 }
14`;
15
16export function MutationWithHOC({ client }) {
17 const [error, setError] = useState(false);
18 const [success, setSuccess] = useState(false);
19 const [email, setEmail] = useState('');
20 const [password, setPassword] = useState('');
21
22 const { mutate } = client;
23
24 const onSubmit = async e => {
25 try {
26 e.preventDefault();
27 const res = await mutate({
28 mutation: LOGIN_MUTATION,
29 variables: {
30 email,
31 password
32 }
33 });
34
35 setSuccess(res.data);
36 } catch (err) {
37 setError(err);
38 }
39 };
40
41 if (error) {
42 alert('Error Logging In User');
43 }
44
45 if (success) {
46 alert('Successfully Logged In');
47 }
48
49 return (
50 <form id="signinForm" className="text-center p-4" onSubmit={onSubmit}>
51 <p className="h4 mb-4 f-1">Sign In</p>
52
53 <input
54 title="Email"
55 id="email"
56 name="email"
57 value={email}
58 onChange={e => setEmail(e.target.value)}
59 type="email"
60 required
61 />
62 <input
63 title="Password"
64 id="password"
65 name="password"
66 type="password"
67 value={password}
68 onChange={e => setPassword(e.target.value)}
69 required
70 />
71
72 <div className="form-group my-4">
73 <button className="btn btn-block" type="submit">
74 Sign In
75 </button>
76 </div>
77 </form>
78 );
79}
80
81export default withApollo(MutationWithHOC);

Conclusion

A lot more can be accomplished with the Apollo Client, like caching, refetching, subscriptions and a whole lot more.

In this article, we looked at how to set up a basic apollo client with react, the different methods we can use to make queries and mutations and also examples of how to make queries and mutations in our react components.

Find the code used in this project on Github

Find more information on Apollo Client here

If you have any questions or feedback about this article, feel free to leave a comment.

Thanks for reading.

More articles from easybuoy

Setting up a Node API with Postgres and Knex

In this article, I would be setting up a Node project with Postgres database and Knex query builder.

September 16th, 2019 · 2 min read

Integrating Continous Integration tools to Node API

Integrating Continous Integration (CI) tools (Travis CI & Coveralls) to a project.

August 27th, 2019 · 2 min read
© 2019 easybuoy
Link to $https://twitter.com/easybuoyLink to $https://github.com/easybuoy/Link to $https://instagram.com/easybuoy19Link to $https://www.linkedin.com/in/easybuoy/