This is the final post on the series of GraphQL posts.
We started with intro to GraphQl, implemented a simple NodeJs GraphQl service to understand the
concepts like Resolvers
, Schemas (typeDefs)
,Query
and Mutation
, and then we built the same GraphQL service in elixir with Absinthe.
In this post, we're going to build the UI using ReactJs and Apollo graphql client for the menu card service we wrote. Let's get started.
Like every React example starts:
Let us add GraphQL dependencies we need:
- @apollo/client is a GraphQL client library to fetch data via GraphQL
- graphql is a core GraphQL library apollo uses
We're ready to code! 👨💻
Edit index.js
:
Update your .env
to
REACT_APP_API_URL=https://localhost:4000
set REACT_APP_GRAPHQL_URL
to the graphql service endpoint you're running.
Lines we added:
The client is the interface between our React app and the GraphQL service, we are telling it to use the service from the provided url and to use configurable cache.
If you already didn't have the GraphQL node server running, start the service and continue or clone the repo:
$ git clone https://github.com/jawakarD/node-graphql-menu.git && cd node-graphql-menu && yarn && yarn start.
For the client
to be consumed by the hooks we use in our Application, pass the App
component as a child to
ApolloProvider
which acts as a context provider and passes the client
as a context.
That's all in index.js
.
Let us move to functionalities:
Don't worry about css, delete the content on App.css
, copy and paste this gist.
Get menu items - useQuery
useQuery
hook allows us to query the graphql service as we did in the server-side playground, but here we are going to
use react to call those queries.
basic usage:
useQuery
takes two parameters
- GraphQL query string, for the query we are going to make
- options will have the variables and other options we can pass
Edit your App.js to have two components MenuItem
and App
:
In the App
component, we call useQuery
hook with GET_MENU_ITEMS
query to fetch the list of menu items.
The hook returns different states of the data that is being fetched: loading, error (if any in the query, actual data for the query, and other values.
The query will also be cached. If same is called again in another component, apollo will fetch the data from the cache that will make the subsequent queries much faster. Another interesting thing is, you can also interact with the stored cache. But it's not recommended to use apollo cache as a state management like redux, because redux will give us more control over updating data than apollo cache.
useQuery
also allows other features: Polling (execute query periodically at a specified interval) and Refetching (Refetch the query).
You might want to opt useLazyQuery
hook for cases where the actual execution of the graphql query needs to happen on some other user action or event,
as opposed to the default behaviour of execution. Read more on this here.
Now, if you turn into the browser, you can see the list of currently available menus. If it's empty, you can wait to add some when we go to the useMutation
section.
Create menu item - useMutation
useMutation
allows us to run mutations with the graphql server.
basic usage:
Like useQuery
, useMutation
takes two arguments: gql query string and mutation options. But like useLazyQuery
it doesn't do any API call on its own
but returns a tuple containig:
- a mutate function is to execute mutation at any time
- an object with state of the mutation:
called
,loading
,data
anderror
To add a new menu item using the UI, add a Form
component, and incorporate that in the App
component.
Edit your App.js to have Form
component and use that in the App
component:
update function:
Here we are passing options to the useMutation
, But we can also pass options to the mutate function when we're calling the addMutation
function.
The options we pass to the mutate function will override the options in useMutation
.
update
function is a callback, that will be called after the a successful mutation, with arguments data
that mutation returns
and the current cache
interface.
Through mutation, you're only updating the server-side data.
If a mutation updates a single existing entity, apollo-graphql will automatically update that entity's value in its cache when the mutation
returns with the updated entity's id
.
Apart from updating, if we are doing other updates(addition and deletion) using mutation, we have to update the cache to reflect the changes manually.
So, understanding update function we are using in above useMutation
:
- Get the cache of the query
GET_MENU_ITEMS
:
cache.writeQuery
used to write data to a specific query, here are updating data ofGET_MENU_ITEMS
query with the newly created data using spread operator:
On submit:
Here, we are passing variables in the options that will be used in the mutation mutation addMenuItem($name: String!, $price: Int!, $rating: Int)
to create a menu item.
Save the file and go to the browser to add a menu item. After you submit the form, you will see the submitted menu item will be added to the list because of the update function.
You can take an exercise to implement deleting a menu item and updating the cache for the delete function.
query
and mutation
are the main things to know in graphql. There's also a topic called subscriptions
, which uses WebSocket to push changes to the client
instead of us querying or mutating.
Thanks.