All Articles

Creating a Reddit Clone Using React and GraphQL - 08

inner peace

From the last blog post, we saw that there is an issue while updating the name on the home page. To fix that we need to add update the cache mechanism. Let’s add the relevant packages for it.

yarn add @urql/exchange-graphcache

Now we need to add the exchanges to createClient in _app.tsx page. Make sure that cacheExchange is coming from @urql/exchange-graphcache . Now we need to have custom update. To do that add the update property to cacheExchange ‘s options. Inside the Mutation Object it needs to match the names.

exchanges: [
  dedupExchange,
  cacheExchange({
    updates: {
      Mutation: {
        login: (result: LoginMutation, args, cache, info) => {
          cache.updateQuery({ query: MeDocument }, (data: MeQuery) => {});
        },
      },
    },
  }),
  fetchExchange,
];

Here, type support is a bit lacking. So we are creating a helper function.

function cacheUpdateQuery<Result, Query>(
cache: Cache,
qi: QueryInput,
result: any,
fn: (r: Result, q: Query) => Query
) {
    return cache.updateQuery(qi, (data) => fn(result, data as any) as any);
}

Now, instead of calling updateQuery inside the Mutation object we can use this function. We are adding cache update for every login and register. Once we replace the code, we will end up with the below code.

login: (_result, args, cache, info) => {
  cacheUpdateQuery<LoginMutation, MeQuery>(
    cache,
    { query: MeDocument },
    _result,
    (result, query) => {
      if (result.login.errors) {
        return query;
      } else {
        return {
          me: result.login.user,
        };
      }
    }
  );
},
register: (_result, args, cache, info) => {
  cacheUpdateQuery<RegisterMutation, MeQuery>(
    cache,
    { query: MeDocument },
    _result,
    (result, query) => {
      if (result.register.errors) {
        return query;
      } else {
        return {
          me: result.register.user,
        };
      }
    }
  );
}

One thing we need to change here that we repeat that the user props all over the graphql queries. So we are moving it to fragment.

Now we are going to add the Logout function. To do that we need to add the logout mutation. In there we can use a request to destroy the session in the server and a response object to clear the cookie.

@Mutation(() => Boolean)
  logout(@Ctx() { req, res }: RedditDbContext) {
    return new Promise((resolver) =>
      req.session.destroy((err) => {
        res.clearCookie(COOKIE_NAME);
        if (err) {
          console.log(err);
          resolver(false);
          return;
        }
        resolver(true);
        // TODO: Seems I need to check this again
      })
    );
}

Now we are coping the GraphQL query and generate the types form the web app.

Here is the logout query from GraphQL Playground.

mutation {
  logout
}

Then add this in the NavBar logout button.

<Button
  onClick={() => {
    logout();
  }}
  isLoading={logoutFetching}
  variant="link"
>

Up to now, we are able to successfully removed the cookie but still, the cache is not updated. So let’s add a new mutation to cacheExchange .

logout: (_result, args, cache, info) => {
cacheUpdateQuery<LogoutMutation, MeQuery>(
  cache,
  { query: MeDocument },
  _result,
  () => {
    return {
      me: null,
    };
  }
);
},

Now once we log out, the cache also set to null .

I will wrap up this post from here. If you have anything to ask regarding this please leave a comment here. Also, I wrote this according to my understanding. So if any point is wrong, don’t hesitate to correct me. I really appreciate you. That’s for today friends. See you soon. Thank you.

References:

This article series based on the Ben Award - Fullstack React GraphQL TypeScript Tutorial. This is amazing tutorial and I highly recommend you to check that out.

Main image credit