Building a Instagram clone in React with GraphQL and Hasura - Part II
Tags: graphql, react, instagram, tutorial
Published: 2019-12-16 13:13:54

---
title: Building a Instagram clone in React with GraphQL and Hasura - Part II
published: true
date: 2019-09-06 09:54:51 UTC
tags: graphql, react, instagram, tutorial
canonical_url: https://blog.hasura.io/instagram-clone-react-graphql-hasura-part2/
---

![](https://blog.hasura.io/content/images/2019/09/Instagram-clone-1.png)

_This tutorial was written by [Abhijeet Singh](https://github.com/abhi40308) and published as part of  the [Hasura Technical Writer Program](https://blog.hasura.io/the-hasura-technical-writer-program/) - an initiative that supports authors who write guides and tutorials for the open source Hasura GraphQL Engine._

In **[part-1](https://blog.hasura.io/instagram-clone-react-graphql-hasura-part1/)** of this series, we setup our backend and Auth0. In this part, we will setup our React app and connect it to our backend.

# React App Setup

We will firstly implement user authentication. We will be using JWT (JSON  web tokens) for authentication. Let’s first create some basic header in our react app for showing login button.

Replace the contents of `styles/App.css` file with [this](https://github.com/abhi40308/instagram-clone/blob/master/src/styles/App.css) file. These styles will be used throughout our app so you don’t have to worry about the styling. Also download [this](https://github.com/abhi40308/instagram-clone/blob/master/src/styles/sprite.png) file and place it in your `styles/` directory. We will use this to show various buttons within our app.

### Setup Apollo GraphQL Client

Replace contents of `App.js` to use Apollo GraphQL client as shown below. ([See apollo github repository for more help](https://github.com/apollographql/react-apollo))

{% gist https://gist.github.com/abhi40308/fd4f54b204e9e0f0b437be2ca21c49d7.js %}

In `line 15` change the `uri` to your GraphQL Endpoint on hasura, which you can find on hasura console (remember where you created tables). Here we have imported the `header` component which we will implement now.

### Create header component and use react-routes:

We will use `react-router` to implement single-page application behaviour. Install `react-router` using:

```
$ npm install react-router-dom
```

> _React  Router, and dynamic, client-side routing, allows us to build a  single-page web application with navigation without the page refreshing  as the user navigates. React Router uses component structure to call  components, which display the appropriate information._


> _By  preventing a page refresh, and using Router or Link, the flash of a  white screen or blank page is prevented. This is one increasingly common  way of having a more seamless user experience. (_[_source_](https://medium.com/@marcellamaki/a-brief-overview-of-react-router-and-client-side-routing-70eb420e8cde)_)_

For using `react-router` in our app, we have to wrap whole app in `BrowserRouter` It is a context provider for routing, which provides several `props` necessary for routing (like `match`, `location`, `history`). See [this](https://reactjs.org/docs/context.html) if you are unfamiliar with context. Replace the contents of `index.js`:

{% gist https://gist.github.com/abhi40308/7d142b7f69be5faa7d15c5a077eca4fb.js %}

Next, we will create a `Header` component for navigation within app. Create a `Header.js` file in `components` directory. The contents of `Header.js` should be:

{% gist https://gist.github.com/abhi40308/e3c4ac34eed811a5139e2194c576d354.js %}

Here we are creating a navbar similar to Instagram navbar. Later we will add some routes to it for navigation. That’s it! We have successfully created a header navbar and used `react-routes` in our app.

![](https://blog.hasura.io/content/images/2019/08/Header.png)<figcaption>Right now your app should look like this</figcaption>

### Auth0 JWT integration with React App

Follow along with [Auth0-react-quickstart](https://auth0.com/docs/quickstart/spa/react/01-login#configure-auth0) guide as reference to include Auth0 in react app. Configure Auth0 client by setting `Allowed Callback URLs`, `Allowed Web Origins`, `Allowed Logout URLs` to [http://localhost:3000](http://localhost:3000/) and add the custom API if you haven’t done already. Now install `auth0-spa-js` :

`$ npm install @auth0/auth0-spa-js`

Now we will include `react-auth0-wrapper` in our app, which is a set of custom [react-hooks](https://reactjs.org/docs/hooks-intro.html) that enable you to work with the Auth0 SDK. Create a new directory `src/auth` and add file `react-auth0-wrapper.js` populate it with code from [here](https://auth0.com/docs/quickstart/spa/react/01-login#install-the-auth0-react-wrapper).

Now add another file as `auth/auth_config.json` in `src/auth` . Populate `auth_config.json` with following code (change the values accordingly):

{% gist https://gist.github.com/abhi40308/8882bd82c757444233b97912cb946aa3.js %}

Now we are ready to include login functionality in our react app. Basically, we will be including a `login` button in header. This button will lead to login through Auth0 with redirect to our `localhost` once login/signup is completed. At the same time login/signup data will be updated in our `User` table in hasura backend due to the Auth0 `rules` we added earlier. Once the login is done, we will get the `accessToken` in JWT format using functions provided by Auth0 SDK in `App.js` . This `accessToken` will then be used as a authorization header in apollo client queries to  backend, thus every query which goes to backend will have authorization  header.

Firstly, change the contents of `index.js` to the following:

{% gist https://gist.github.com/abhi40308/9cf917ae180479230be534b72d783cb6.js %}

Here, we are using the `Auth0Provider` which is a context provider for Auth0 client. Any children components will now have access to the Auth0 client.

Having provided the Auth0 client to our app, we now replace the contents of `components/Header.js` file to the following:

{% gist https://gist.github.com/abhi40308/9e0a11d9fa615134dc53d61b2c28af62.js %}

We are using `useAuth0` hook (line 7) to make use of various functions provided by Auth0. `isAuthenticated` is used to check if user is logged in or not. `loginWithRedirect` is used to login and redirect after login to specified redirect-url. `user` object has information about the current logged in user.

Here,  if the user is logged in, we will take user to user-profile, which we  will implement later. If the user is logged out, we will just show login  button.

Now we will make changes in our `App.js` to include Auth0 functionality. Change the contents of App.js to the following:

{% gist https://gist.github.com/abhi40308/0a65f7d9f3af36d67112732e6fbced6c.js %}

We are using `useState` hook(line 22) to set initial `accessToken` value to empty string. If the user is logged in, the token is fetched from the Auth0 SDK client using `getTokenSilently()` (line 33). Notice that this function returns a `Promise` and is asynchronous. This function attempts to return the current access token. If the token is invalid, the token is refreshed silently before being returned from the function. If the `try` block successfully gets executed, `accessToken` value is set to the JWT access-token from Auth0 (line 34).

The component re-renders when we get `accessToken` value. Thus after the async function has finished executing, we store the value of `accessToken` in state. The component re-renders and apollo-client gets the token value, thus re-rendering the whole `ApolloProvider` (context-provider) with new token value and the authentication header.

Once we have accessToken, we will use this to make requests to our backend using apollo client. See [apollo-docs](https://www.apollographql.com/docs/react/recipes/authentication/#header) for apollo authentication using headers. Basically, we are passing the `accessToken` as authorization header(line 52), in our apollo queries. This client is then used inside the `ApolloProvider`(context provider) to provide the child elements access to apollo client created here.

Now,  you should be able to login in our app. Clear cache and login. You must  be asked to give access to your auth0 tenant by our hasura backend.  Give the access and you’re good to go.

> _Note : If you are facing errors, remember to not keep any dependency on_ `react-apollo` _._ `@apollo/react-hooks` _must be used instead._

![](https://blog.hasura.io/content/images/2019/08/header_2.png)<figcaption>Now our app looks like this</figcaption>

## Implementing Feed and Likes(realtime updates of Likes)

We will implement a list of posts (feed) and a like button. Create a new component `components/Feed.js` as:

{% gist https://gist.github.com/abhi40308/ce33d45e6923831d4ba28be1d1ecc8f2.js %}

`POSTS_LIST` query(line 8) is being used to fetch details from `Post` table in our database. We are querying the id of the post.`useQuery` (line 18) is a custom [apollo-client react hook](https://www.apollographql.com/docs/react/api/react-hooks/). We get the query data in `data` object (line 18) which is then passed as a prop to the `Post` component, which we will implement now.

Create a new component `components/Post.js` as:

{% gist https://gist.github.com/abhi40308/b457b7cae4079f48d3ee0a3fac18eaa7.js %}

Here, we are getting the props passed by `Feed.js` component and using the `id` prop, we are getting the complete post data using `POST_INFO` query. We are then rendering the data with styling in `return` statement. We are using function `timeDifferenceForDate` (line 68) for converting `post.created_at` to instagram style time. Now we need to implement this function. We are  also importing Like component which takes care of like functionality,  which we will implement later.

Create a new directory `src/utils` and create a new file `TimeDifference.js` as:

{% gist https://gist.github.com/abhi40308/b5458e7c15b817d18d7e624be7859793.js %}

It is just a utility function to convert the date-time data into our required format.

Now we will implement the `Like` component. Create a new file `components/Like.js` as:

{% gist https://gist.github.com/abhi40308/ee584d4c35c8964dbd846be3d6ca929c.js %}

`Like` components gets the `post_id` through props. Here we are writing two mutations and one query. `FETCH_LIKES` is used to fetch the number of likes from `Post` table. Also we are fetching whether the currently logged in user has already liked the post (line 15). `LIKE_POST` and `DELETE_LIKE` are used to insert a like in `Like` table and delete from `Like` table respectively.

We are storing `countLikes` (number of likes) and `liked` (if the user like the post) in state variables. As the state changes,  the Like component re-renders which gives us updated view if user likes  the post. If the user likes the post, we are showing a red heart,  otherwise a white heart in UI. To implement this, we are checking value  of `liked` (line 104) and rendering  buttons accordingly. As the user likes the post, state changes (line  109), component re-renders, and like mutation occurs (line 108) which  records the like in database, and number of likes is increased (line  110).

We have two mutations, submitting the like (line 58) and deleting the like(line 69). Both mutations uses `refetchQueries` argument (line 60) which is used to refetch the query `FETCH_LIKES`, thus updating the apollo cache with new values. This implements real-time likes.

We now have all the components in place to implement post feed. We need to change `App.js` to include `Feed.js`. Make following changes in your `App.js`:

{% gist https://gist.github.com/abhi40308/ce8092697db1366c16e3004142f0f521.js %}

[`Switch`](https://reacttraining.com/react-router/web/guides/basic-components) is a part of react-router which is used to match components with their  paths. Insert some random data (posts) from Hasura Console in `Post` table try the app.

![](https://blog.hasura.io/content/images/2019/08/Final_app.png)<figcaption>Now our app looks like this</figcaption>

Try liking posts, and see the real-time updates in likes, thanks to `refetchQueries` . We haven’t yet implemented the user-profile, so the user profile links won’t work. Next we will implement the same.

# Implementing User Profile

Our user profile will have instagram style UI with user information on top and grid of posts uploaded by user at bottom. We will implement profile in two components, one will take care of rendering the main UI and the  other will handle follow functionality.

Create a new component `components/Profile.js` as:

{% gist https://gist.github.com/abhi40308/3691b3a877b5c95891396254a1522d56.js %}

We  have three different queries, which will fetch all the basic data of  user to be displayed. Notice that we could have called all the queries  in one go, but while refetching the queries in case of follow mutation,  we will have to refetch all the data to update cache, but only follow  data would have changed. Thus we have made two separate queries for `NUMBER_OF_FOLLOWERS`(line 41)  and `NUMBER_OF_FOLLOWING`(line 31). We have exported these queries, thus while implementing `Follow` component, we will be able to import and refetch the queries. This will  become more clear once we start implementing follow functionality.

We are getting `user_id` as props which will be used to query our backend database for user info, for the given `user_id`. The data is then rendered in `return()` . The props (`user_id`) here is being passed in form of url, and we are using `props.match.params.id` to get that prop. These props are provided by the react-router `BrowserRouter` context provider, which is included in our `index.js `file.

Query `USER_INFO` is used to fetch data from  table `User` and `Post`.  In line 103, we are checking if currently displayed profile is same as  the user currently logged-in. In that case we will show a Logout button.  If the profile is of other users, we will show a Follow button instead.  `isLoggedUser` function is used to check this condition. Follow button is implemented in Follow component which we will implement next.

Also we are using `react-bootstrap` rows to implement posts grid at the bottom of user profile, with three  items per row (line 147). Each post item in the grid is a clickable link  which leads to the respective post. Here, we are passing `id` as props through the url (`to={“/post/” + post.id}`) in line 148, which is accessed via `props.match.params.id` in the receiving component. This is a react-router way of passing prop. See [this](https://reacttraining.com/react-router/web/example/url-params) example for more details.

Now, we will implement `Follow` component. Create a new file `component/Follow.js` as:

{% gist https://gist.github.com/abhi40308/cf881730e94879687d6d65f6676c434f.js %}

This is identical to `Like` component. It is being fetched whether the currently logged in user follows the currently rendered profile using `FETCH_FOLLWERS` query. If data returned by `FETCH_FOLLWERS` is not empty, we will initially set `followed` state to `true` (line 115). Here, we are using a state `followed`(line 49) to check whether current user follows the displayed profile and a `ref` variable `firstRun`(line  52) which checks if the component is being rendered for the first time,  which is useful as we want to do certain operations(line 112) on first  time rendering of the component only, like setting the state `followed` to true or false initially depending on data returned from query `FETCH_FOLLWERS`.

Also we are using two mutations `FOLLOW_USER` and `UNFOLLOW_USER` which are inserting and deleting data from `Follow` table in our backend. Notice that both these mutations refetch three  queries (line 66) in order to update apollo cache with correct data  after the mutation. This automatically implements real-time data  updates, where as soon as the mutation is performed, the number of  followers of the displayed profile, and the number of following of the  logged-in user updates.

Now, we will make the required changes in `App.js`. But firstly create a new file as `components/SecuredRoute.js` as:

{% gist https://gist.github.com/abhi40308/84155ad7baf02ec5961b8fb8c89db2d6.js %}

This  will help us to create some secured routes which can only be accessed  if the user is logged-in. We will use secured routes while routing.  Using secured route, if someone tries to access the url’s without  logging-in, user will be redirected to login automatically.

Now make the following changes in `App.js` :

{% gist https://gist.github.com/abhi40308/60a2919a4ad8fe0c9a8cad67d460fa94.js %}

Now, you should be able to visit user profiles. Insert some sample data  from Hasura console, and see the user profiles and follow functionality.  See the real-time update in follow functionality.

![](https://blog.hasura.io/content/images/2019/08/Now_app3.png)<figcaption>User profile looks like this</figcaption>

## Implementing Submit Post functionality

Create a new file `components/Upload.js` as:

{% gist https://gist.github.com/abhi40308/e4ee29a8b2070b01315ca8a24b984dd2.js %}

`SUBMIT_POST` mutation is used to make a entry in our database table `Post`. We are using `react-bootstrap` modal to show a popup box to enter values of `url` and `caption`. Currently, image uploading is not supported, as we are not implementing any storage service to store images.

We have a `form` (line 48) which has two input fields for `caption` and `url`. We are using react state to store values of `caption`, `url` and `error` (if mutation is not successful). If the form is submitted, `submitPost` mutation is called which changes the data and `refetchQueries` updates data in apollo cache for queries `POST_LIST` and `USER_INFO` thus updating the feed and user profile respectively.

Now we will do the required changes in `App.js` :

{% gist https://gist.github.com/abhi40308/99cca6e56a9447bb3b96933944738b70.js %}

If the user is authenticated, we will show a upload button which will open the following popup when clicked:

![](https://blog.hasura.io/content/images/2019/08/Upload.png)

Finally,  we have our app ready with upload post functionality. You can navigate  to user-profiles, create new posts and see real-time updates of  new-posts, likes and follows.

You should now have a working Instagram clone. Incase you'd like to reference it, the final code for this app is hosted [here](https://github.com/abhi40308/instagram-clone). See live demo of the app [here](https://instagram-1919.herokuapp.com/).

## **Acknowledgements** :

TimeDifference function: [https://github.com/howtographql/react-apollo](https://github.com/howtographql/react-apollo)

Few Styles taken from : [https://pusher.com/tutorials/instagram-clone-part-1](https://pusher.com/tutorials/instagram-clone-part-1)

## About the author 

[Abhijeet Singh](https://github.com/abhi40308) is final year UG student in Computer  Science and Engineering from IIIT Kalyani. He has done work in Full  Stack Development, Android, Deep Learning, Machine Learning and NLP. He actively takes part in competitive programming contests and has interest  in solving algorithmic problems. He is a startup enthusiast and plays  table tennis and guitar in spare time.