Apollo Client with React Hooks

Apollo Hooks

  • useQuery

  • useMutation

Why hooks are the future?

  • Less data management code

  • Multiple mutations

  • Improved TypeScript support

  • Lazy evaluation for queries

  • 50% bundle size reduction

Less data management code

Render prop

const GET_DOGS = gql`
  {
    dogs {
      id
      name
    }
  }
`;
const Dogs = () => (
  <Query query={GET_DOGS}>
    {({ loading, error, data }) => {
      if (loading) return 'Loading...';
      if (error) return `Error! ${error.message}`;

      return (
          {data.dogs.map(dog => (
            <div> {dog.name} </div>
          ))}
      );
    }}
  </Query>
);

Hooks

const GET_DOGS = gql`
  {
    dogs {
      id
      name
    }
  }
`;

function Dogs() {
  const { loading, error, data } = useQuery(GET_DOGS);

  if (loading) return 'Loading...';
  if (error) return `Error! ${error.message}`;

  return (
      {data.dogs.map(dog => (
        <div>{dog.name} </div>
      ))}
  );
}

Multiple mutations

function Message() {
  const [saveMessage, { loading }] = useMutation(SAVE_MESSAGE);
  const [deleteMessage] = useMutation(DELETE_MESSAGE);
  const { data } = useQuery(GET_MESSAGE);

  return (
    <div>
      <p>
        {loading
        ? 'Loading ...'
        : `Message: ${data && data.message ? data.message.content : ''}`}
      </p>
      <p>
        <button onClick={() => saveMessage()}>Save</button>
        <button onClick={() => deleteMessage()}>Delete</button>
      </p>
    </div>
  );
}

Improved TypeScript support

import { RocketData, RocketVars } from './types';

const GET_ROCKET_INVENTORY = gql`
  query getRocketInventory($year: Int!) {
    rocketInventory(year: $year) {
      year
    }
  }
`;

export function RocketInventoryList() {
  const { loading, data } = useQuery<RocketData, RocketVars>(
    GET_ROCKET_INVENTORY,
    { variables: { year: 2019 } }
  );
  return (/* ... show data ... */);
}

Lazy evaluation for queries

const GET_INVENTORY = gql`
  query invetory {
      id
      name
  }
`;

const [execute, { loading, data }] = useLazyQuery(GET_INVENTORY);

50% bundle size reduction

  • react-apollo@2 10.6kB
  • react-apollo@3   7.8kB

How to test hooks?

import { useState, useCallback } from 'react'

function useCounter() {
  const [count, setCount] = useState(0)

  const increment = useCallback(() => setCount((x) => x + 1), [])

  return { count, increment }
}

export default useCounter

React hooks testing library

import { renderHook, act } from '@testing-library/react-hooks'
import useCounter from './useCounter'

test('should increment counter', () => {
  const { result } = renderHook(() => useCounter())

  act(() => {
    result.current.increment()
  })

  expect(result.current.count).toBe(1)
})

Apollpo client with react hooks

By jingliu

Apollpo client with react hooks

  • 311