More Mutations and Updating the Store

The next piece of functionality that you’ll implement is the voting feature! Authenticated users are allowed to submit a vote for a link.

Preparing the Component

Once more, the first step to implement this new feature is to make your component ready for the expected functionality.

You’re preparing the link-post component to render the number of votes for each link and the name of the user that posted it. Plus you’ll render the upvote button if a user is currently logged in - that’s what you’re using the userId for. If the Link is not associated with a User, the user’s name will be rendered as Unknown.

Notice that you’re also using several helpers including moment-from-now that gets passed the createdAt information for each link. The helper will take the timestamp and convert it to a string that’s more user friendly, e.g. "3 hours ago".

Go ahead and add the moment-from-now and add helpers next.

Notice that the app won’t run at the moment since the votes are not yet included in the query. You’ll fix that next!

Updating the Schema

For this new feature, you also need to update the schema again since votes on links will be represented with a custom Vote type.

Each Vote will be associated with the User who created it as well as the Link that it belongs to. You also have to add the other end of the relation.

Here is what the Terminal output looks like:

$ gc push
 ✔ Your schema was successfully updated. Here are the changes: 

  | (+)  A new type with the name `Vote` is created.
  |
  | (+)  The relation `UsersVotes` is created. It connects the type `User` with the type `Vote`.
  |
  | (+)  The relation `VotesOnLink` is created. It connects the type `Link` with the type `Vote`.

Your project file project.graphcool was updated. Reload it in your editor if needed.

Awesome! Now that you updated the schema, you can fix the issue that currently prevents you from properly running the app. It can be fixed by including the information about the links’ votes in the allLinks query.

All you do here is to also include information about the user who posted a link as well as information about the links’ votes in the query’s payload. You can now run the app again and the links will be properly displayed.

Time to move on and implement the upvote mutation!

Calling the Mutation

This step should feel pretty familiar by now. You’re adding the ability to call the createVote mutation to the link-post component.

Notice that in the first part of the method, you’re checking whether the current user already voted for that link. If that’s the case, you return early from the method and not actually execute the mutation.

You can now go and test the implementation! Run yarn start and click the upvote button on a link. You’re not getting any UI feedback yet, but after refreshing the page you’ll see the added votes.

There still is a flaw in the app though. Since the votes on a link-post don’t get updated right away, a user currently can submit an indefinite number of votes until the page is refreshed. Only then the protection mechanism will apply and instead of an upvote, the click on the voting button will simply result in the following logging statement in the console: User (cj42qfzwnugfo01955uasit8l) already voted for this link.

But at least you know that the mutation is working. In the next section, you’ll fix the issue and make sure that the cache gets updated directly after each mutation!

Updating the Cache

One cool thing about Apollo is that you can manually control the contents of the cache. This is really handy, especially after a mutation was performed, since this allows you to determine precisely how you want the cache to be updated. Here, you’ll use it to make sure the UI displays the correct number of votes right after the createVote mutation was performed. You can implement this functionality by using Apollo’s imperative store API.

The update function that you’re adding as an argument to the mutation call will be called when the server returns the response. It receives the payload of the mutation (data) and the current cache (store) as arguments. You can then use this input to determine a new state of the cache.

Notice that you’re already destructuring the server response and retrieving the createVote field from it.

What’s going in the update function?

  1. You start by reading the current state of the cached data for the allLinks query from the store.
  2. Now you’re retrieving the link that the user just voted for from that list. You’re also manipulating that link by resetting its votes to the votes that were just returned by the server.
  3. Finally, you take the modified data and write it back into the store.

While you’re at it, also implement update for adding new links!

The update function works in a very similar way as before. You first read the current state of the results of the allLinks query. Then you insert the newest link to the top and write the query results back to the store.

Awesome, now the store also updates with the right information after new links are added. The app is taking shape. 🤓

Unlock the next chapter
What does the 'graphcool push' command do?
It uploads the local schema changes to the remote Graphcool project
It pushes a git repository to Graphcool so you can manage your project and code together
It tells the server to push its remote schema changes into the local project file
There is no 'graphcool push' command