apollo-client useMutation 정리

HyosikPark·2020년 12월 21일
1

graphql

목록 보기
8/8
import { useMutation, gql } from '@apollo/client';

const LOGIN = gql`
  mutation login($email: String!, $password: String!) {
    login(loginInput: { email: $email, password: $password }) {
      id
      nickname
      email
      createdAt
      token
    }
  }
`;

const Login = () => {
  const [value, setValue] = useState({
    email: '',
    password: '',
  });

  const [login, { data, error, loading }] = useMutation(LOGIN, {
    variables: value,
    errorPolicy: 'all',
  });

  const onSubmit = useCallback((e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    login(); // useMutation실행
  }, []);

useMutation의 두번째 인자에 variables 등의 옵션을 넣는것도 가능하지만 실행인자에 login({variables: ...}) 으로 넣는 것도 가능.

useMutation사용 시 생각해볼 수 있는 문제점이 있는데 예를 들어 회원가입을 한 모든유저를 어떠한 화면에 나타내주려고 한다면 useQuery로 데이터베이스에 저장된 모든 회원을 받아온다음 캐시에 저장해 클라이언트에서 map 함수로 나타내 줄 것이다.

만약 누군가 useMutation으로 회원가입을 한다면 데이터베이스에 추가가 되고 이미 렌더링 되어있는 UI에 자동으로 회원이 추가된 결과가 반영되어야 할것이다.

그러기위해서는 저장된 캐시의 data가 업데이트되어야 한다.
이때 apollo client는 useMutation resolver에서 반환한 id값을 통해 수정된 정보를 인지하게 되므로 resolver에서 데이터를 return할 때는 각 데이터마다 구분되는 id를 포함하여 같이 return시켜줘야한다.

하지만 여러 데이터를 수정할 경우에는 업데이트가 반영되지 않으므로 update 옵션을 사용해야한다.

const [login, { error, loading }] = useMutation(LOGIN, {
    variables: value,
    errorPolicy: 'all',
    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 함수는 cache와 mutation으로 받아온 data를 인자로 넘겨준다.
cache는 readQuery, writeQuery, readFragment, writeFragment, modify. 메소드를 실행할 수 있다.
캐시가 원하는 데이터를 가공하여 캐시 스스로 캐시데이터를 업데이트할 수 있다.

refetchQueries 옵션으로 mutation 후 원하는 쿼리를 리렌더링 하는 간편한 방법도 있지만 query에서 return해야할 데이터가 큰 경우 예를들어 1000개의 게시글을 받아오는데 mutation으로 게시글 1개를 늘려서 1001개의 데이터를 다시 불러오는것은 굉장히 비효율적이다.

참고할만한 options

variables: {[key:string] : any}
mutation요청에 필요한 변수를 주입할 때 사용

update(cache,data) {}
mutation 요청 후 cache를 업데이트 하기 위해 사용

ignoreResults : boolean
data는 그대로 받아오지만 결과를 업데이트 하지는 않음.

optimisticResponse : Object
mutation 수행 후의 결과로 UI가 변화하는 경우 결과를 받아오기까지의 시간을 기다리지않고 적용시켜주는 기능.

refetchQueries : [Query: DocumentNode, variables]
mutation과 동시에 비동기적으로 원하는 쿼리를 refetch한다.

awaitRefetchQueries : boolean
mutation 결과를 받아 온 후 refetch 실행

onCompleted(data) => void
mutation 결과를 받아 온 후 실행되는 콜백함수

onError(err) => void
err시 실행되는 콜백함수

참고할만한 results

data : 반환된 데이터

loading : 실행 중 true

error : 실패시 err

called : boolean
mutation 실행 여부

0개의 댓글