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 id5 name6 email7 }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 id5 name6 email7 created_at8 }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';34const client = new ApolloClient({5 uri: 'https://rickandmortyapi.com/graphql/' //URL of the GraphQL server6});
…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';45const GET_CHARACTERS = gql`6 query getCharacters {7 characters {8 results {9 id10 name11 image12 }13 }14 }15`;1617export 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}`;2324 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';45const GET_CHARACTERS = gql`6 query getCharacters {7 characters {8 results {9 id10 name11 image12 }13 }14 }15`;1617function CharacterWithHook() {18 const { loading, error, data } = useQuery(GET_CHARACTERS);19 if (error) {20 return <div>Error</div>;21 }2223 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}4546export 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';45const GET_CHARACTERS = gql`6 query getCharacters {7 characters {8 results {9 id10 name11 image12 }13 }14 }15`;1617function CharacterWithHOC({ client }) {18 const [characters, setCharacters] = useState([]);1920 client21 .query({ query: GET_CHARACTERS })22 .then(res => setCharacters(res.data.characters.results))23 .catch(err => console.log(err));2425 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}4344export 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';45const LOGIN_MUTATION = gql`6 mutation userLogin($email: String!, $password: String!) {7 userLogin(email: $email, password: $password) {8 username9 email10 id11 token12 }13 }14`;1516export default function MutationWithRender() {17 const [email, setEmail] = useState('');18 const [password, setPassword] = useState('');1920 return (21 <Mutation mutation={LOGIN_MUTATION}>22 {(loginUser, { loading, error, data }) => {23 if (loading) return 'Loading...';24 if (error) return `Error! ${error.message}`;2526 return (27 <form28 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>3637 <input38 title="Email"39 id="email"40 name="email"41 value={email}42 onChange={e => setEmail(e.target.value)}43 type="email"44 required45 />46 <input47 title="Password"48 id="password"49 name="password"50 type="password"51 value={password}52 onChange={e => setPassword(e.target.value)}53 required54 />5556 <div className="form-group my-4">57 <button className="btn btn-block" type="submit">58 Sign In59 </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';45const LOGIN_MUTATION = gql`6 mutation userLogin($email: String!, $password: String!) {7 userLogin(email: $email, password: $password) {8 username9 email10 id11 token12 }13 }14`;1516export function MutationWithHook() {17 const [email, setEmail] = useState('');18 const [password, setPassword] = useState('');1920 const [loginUser, { data, error, loading }] = useMutation(LOGIN_MUTATION);2122 if (error) {23 alert('Error Logging In User');24 }2526 if (data) {27 alert('Successfully Logged In');28 }2930 return (31 <form32 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>4041 <input42 title="Email"43 id="email"44 name="email"45 value={email}46 onChange={e => setEmail(e.target.value)}47 type="email"48 required49 />50 <input51 title="Password"52 id="password"53 name="password"54 type="password"55 value={password}56 onChange={e => setPassword(e.target.value)}57 required58 />5960 <div className="form-group my-4">61 <button className="btn btn-block" type="submit">62 Sign In63 </button>64 </div>65 </form>66 );67}6869export 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';45const LOGIN_MUTATION = gql`6 mutation userLogin($email: String!, $password: String!) {7 userLogin(email: $email, password: $password) {8 username9 email10 id11 token12 }13 }14`;1516export 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('');2122 const { mutate } = client;2324 const onSubmit = async e => {25 try {26 e.preventDefault();27 const res = await mutate({28 mutation: LOGIN_MUTATION,29 variables: {30 email,31 password32 }33 });3435 setSuccess(res.data);36 } catch (err) {37 setError(err);38 }39 };4041 if (error) {42 alert('Error Logging In User');43 }4445 if (success) {46 alert('Successfully Logged In');47 }4849 return (50 <form id="signinForm" className="text-center p-4" onSubmit={onSubmit}>51 <p className="h4 mb-4 f-1">Sign In</p>5253 <input54 title="Email"55 id="email"56 name="email"57 value={email}58 onChange={e => setEmail(e.target.value)}59 type="email"60 required61 />62 <input63 title="Password"64 id="password"65 name="password"66 type="password"67 value={password}68 onChange={e => setPassword(e.target.value)}69 required70 />7172 <div className="form-group my-4">73 <button className="btn btn-block" type="submit">74 Sign In75 </button>76 </div>77 </form>78 );79}8081export 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.