Apollo Client Fetching

TwentyFiveSeven·2021년 5월 14일
1
post-custom-banner

사용법보다는 내부적 동작, 의미에 집중해서 작성해보겠습니다.

Queries

Caching query results

const { loading, error, data } = useQuery(GET_DOG_PHOTO, {
  variables: { breed },
});
  • Apollo Client는 요청 결과를 자동으로 로컬로 캐시합니다.
  • 위 예시에서 breed를 불독으로 요청하고 breed를 푸들로 요청한 다음에 다시 불독으로 요청하게 되면 로콜에 캐시된 데이터를 사용하기 때문에 처음 요청보다 빠르게 불독의 이미지를 보여줄 수 있는 것을 확인할 수 있습니다.

Updating cached query results

캐시된 데이터가 서버에서 최신 상태인지 확인할 수 있는 방법에는 polling & refetching 방법이 존재합니다.

Polling

  • Polling 방식은 지정된 간격을 갖고 주기적으로 query를 실행시켜 서버와 near-real-time으로 동기화를 제공합니다.
  • Polling을 사용하기 위해서는 useQuery hook에 pollInterval 옵션을 줘야합니다.
const { loading, error, data } = useQuery(GET_DOG_PHOTO, {
  variables: { breed },
  pollInterval: 500,
});

Refetching

  • Refetching 방식은 사용자의 특정 행동에 대한 응답으로 query의 결과를 refresh 할 수 있습니다.
const { loading, error, data, refetch } = useQuery(GET_DOG_PHOTO, {
  variables: { breed }
});

Inspecting loading states

  • 우리가 polling 하거 refetching을 할 때는 데이터를 fetching하고 있다는 렌더링이 되지 않아 알 수 없습니다.
  • 이같은 방법을 해결하기 위해 useQuery hook의 결과는 networkStatus 속성을 통해 쿼리 상태에 대한 세분화 된 정보를 제공합니다.
  • networkStatus를 사용하기 위해서는 notifyOnNetworkStatusChange 옵션을 true로 설정하여 refetch 되는 동안 query component 요소가 다시 렌더링 되도록 합니다.
import { NetworkStatus } from '@apollo/client';

function DogPhoto({ breed }) {
  const { loading, error, data, refetch, networkStatus } = useQuery(
    GET_DOG_PHOTO,
    {
      variables: { breed },
      notifyOnNetworkStatusChange: true,
    },
  );

  if (networkStatus === NetworkStatus.refetch) return 'Refetching!';
  if (loading) return null;
  ...
}

Executing queries manually

  • React가 컴포넌트를 마운트하고 렌더링할 때 useQuery를 호출하지만, 버튼을 클릭하는 것과 같은 이벤트가 발생했을 때 요청을 보내고 싶은 경우에는 useLazyQuery를 사용한다.
  • useLazyQuery는 즉각적으로 실행하지 않고 요청을 위한 함수를 반환합니다.
import React from 'react';
import { useLazyQuery } from '@apollo/client';

function DelayedQuery() {
  const [getDog, { loading, data }] = useLazyQuery(GET_DOG_PHOTO);

  if (loading) return <p>Loading ...</p>;

  return (
    <div>
      {data && data.dog && <img src={data.dog.displayImage} />}
      <button onClick={() => getDog({ variables: { breed: 'bulldog' } })}>
        Click me!
      </button>
    </div>
  );
}

Setting a fetch policy

const { loading, error, data } = useQuery(GET_DOGS, {
  fetchPolicy: "network-only"
});
  • cache-first : default 값으로, 캐시를 먼저 확인하고 요청된 데이터가 캐시에 존재한다면 바로 반환해주고, 만약 존재하지 않는다면 GraphQL Server에게 요청하고 해당 데이터를 캐시에 저장합니다.
  • cache-only : 오직 캐시에만 요청을 하며 서버에게 절대 요청하지 않습니다. 만약 데이터가 존재하지 않는다면 에러를 반환합니다.
  • cache-and-network : 캐시와 GraphQL 서버 모두에게 요청을 합니다. 서버측의 데이터가 변경 되었으면 cache의 값을 변경해줍니다.
  • network-only : 캐시를 체크하지 않고, GraphQL 서버에게 요청을 보내고, 요청의 결과값을 캐시에 저장합니다.
  • no-cache : network-only와 유사하지만 캐시에 저장하지 않는다는 차이점이 있습니다.
  • standby : cache-first와 동일한 놀리로 진행이 되지만, 기본 field 값이 변경 될 때 쿼리가 자동으로 업데이트 되지 않는다는 차이점이 있습니다.

Mutation

Updataing the cache after a mutation

mutation을 실행하게 되면 서버측 데이터가 변경되고 cache에 변경된 데이터를 반영해야한다.

Updating a single existing entity

  • 만약 mutationd으로 a single existing entity를 업데이트를 한다면 mutation이 반드신 id를 반환하면 된다.
  • Apollo Client는 id로 entity를 cache하기 때문이다.

Making all other cache updates

  • mutation으로 다중 entity들을 수정하거나 생성, 삭제하게 되면 Apollo Client cache는 자동적으로 결과를 업데이트 할 수 없습니다.
const GET_TODOS = gql`
  query GetTodos {
    todos {
      id
    }
  }
`;

function AddTodo() {
  let input;
  const [addTodo] = useMutation(ADD_TODO, {
    update(cache, { data: { addTodo } }) {
      cache.modify({
        fields: {
          todos(existingTodos = []) {
            const newTodoRef = cache.writeFragment({
              data: addTodo,
              fragment: gql`
                fragment NewTodo on Todo {
                  id
                  type
                }
              `
            });
            return [...existingTodos, newTodoRef];
          }
        }
      });
    }
  });
  ...
}
  • 이 문제를 해결하기 위해여 update function을 포함한 useMutation 을 사용합니다.
  • update function의 목적은 캐시된 데이터를 변경하는 것 입니다.
  • ADD_TODO mutation이 실행되도, GET_TODOS query로 받은 데이터는 자동적으로 업데이트 되지 않습니다.
  • 때문에 cache.modify를 통해 캐시를 수정하고 삭제할 수 있습니다.
  • GET_TODOS query의 결과가 캐시의 ROOT_QUERY.todos 배열로 저장되어있기 때문에 todos modifier function을 통해 캐시된 데이터를 업데이트 시킬 수 있습니다.

이후 추가 할 내용

Subscriptions

Fragments

Error handling

profile
부지런한 웹개발자🌙
post-custom-banner

0개의 댓글