DEV Community

loading...

Using React Hooks to simplify Apollo Client

jleblanc profile image Josh LeBlanc ・2 min read

I've been enjoying using apollo over the past few months, but one of my biggest pain points was dealing with graphql SDL scattered about the application, tiny queries just for local state, and writing a fair amount of boilerplate to get anything done.

For example, if you want to utilize bits and pieces of your local state for your components, you need to write something like this:

const GET_TOKEN = gql`
  {
    token @client
  }
`;

export default () => {
  const { data } = useQuery(GET_TOKEN);
  return <p>{data.token}</p>
}
Enter fullscreen mode Exit fullscreen mode

That's a lot of boilerplate for what is just reading state.

What I've been using more recently, is moving all of the boilerplate into a hook.

// useToken.js
const GET_TOKEN = gql`
  {
    token @client
  }
`;
export default () => {
  const { data } = useQuery(GET_TOKEN);
  return data.token;
}
Enter fullscreen mode Exit fullscreen mode

Now, when I want to read the token from the cache, all I have to do is call the hook.

// Token.jsx
export default () => {
  const token = useToken();
  return <p>{token}</p>
}
Enter fullscreen mode Exit fullscreen mode

This isn't limited to just queries, and to certainly isn't limited to a single query/mutation per hook. Consider wanting to manage to state of a drawer in your app. You need to know if it's open or closed, and you want to be able to toggle that state.

// useDrawer.js
export const GET_DRAWER_OPEN = gql`
  {
    drawerOpen @client
  }
`;

export const TOGGLE_DRAWER_OPEN = gql`
  mutation ToggleDrawerOpen {
    toggleDrawerOpen @client
  }
`;

export default () => {
  const { data } = useQuery(GET_DRAWER_OPEN);

  return {
    drawerOpen: data.drawerOpen,
    toggleDrawerOpen: useMutation(TOGGLE_DRAWER_OPEN)
  }
}

Enter fullscreen mode Exit fullscreen mode

You can also use these hooks in other hooks! Imagine a scenario where you need to get a user based on the current token. We already have a hook for the token, now all we need is a hook for the user.

// useCurrentUser.js
const GET_CURRENT_USER = gql`
  query GetCurrentUser($token: String) {
    currentUser(token: $token) {
      id
      username
      avatar
      email
    }
  }
`;

export default () => {
  const token = useToken();
  return useQuery(GET_CURRENT_USER, {
    variables: {
      token
    }
  });
}
Enter fullscreen mode Exit fullscreen mode

Now, whenever you want the current user, you just use the useCurrentUser hook and you've got everything you need!

Using this method, I've consolidated all of the graphql SDL and logic into a hook that can be called within any functional component. In addition, the graphql SDL can be exported from the hook for use outside of your components.

I'm using apollo-react-hooks for the useQuery and useMutation hooks.

Discussion (1)

Collapse
davybello profile image
Bello Oladipupo

I've been using this pattern for a while and it's great for react apollo with a few tweaks the same concept applies to render props.

Not sure if there's a name for it been unofficially calling it the data provider pattern.

I try to keep the provider totally seperated from the UI and the containers stateless all/most of the functionality from validation to input changes happens inside the hooks/render props

Forem Open with the Forem app