[Apollo] 4장. Local state management

Apollo 써보기

출처 : Apollo 공식 레퍼런스

목차


Local state management


Updating local state

Direct writes

function FilterLink({ filter, children }) {
  const client = useApolloClient();
  return (
    <Link
      onClick={() => client.writeData({ data: { visibilityFilter: filter } })}
    >
      {children}
    </Link>
  );
}
const GET_VISIBILITY_FILTER = gql`
  {
    visibilityFilter @client
  }
`;

function FilterLink({ filter, children }) {
  const { data, client } = useQuery(GET_VISIBILITY_FILTER);
  return (
    <Link
      onClick={() => client.writeData({ data: { visibilityFilter: filter } })}
      active={data.visibilityFilter === filter}
    >
      {children}
    </Link>
  )
}

Local Resolvers

const client = new ApolloClient({
  cache: new InMemoryCache(),
  resolvers: {
    Mutation: {
      toggleTodo: (_root, variables, { cache, getCacheKey }) => {
        const id = getCacheKey({ __typename: 'TodoItem', id: variables.id }) // 캐시를 찾을 키 값
        const fragment = gql`
          fragment completeTodo on TodoItem {
            completed
          }
        `;
        const todo = cache.readFragment({ fragment, id }); // 캐시의 fragment를 읽어옴
        const data = { ...todo, completed: !todo.completed };
        cache.writeData({ id, data }); // 캐시에 반영해준다
        return null; // UI에 결과를 반영해 줄 필요는 없는 듯!
      },
    },
  },
});

저렇게 캐시 업데이트를 설정해두고, 실제로 업데이트를 쳐보자!

const TOGGLE_TODO = gql`
  mutation ToggleTodo($id: Int!) { // 업데이트 해야 할 id를 넘겨준다
    toggleTodo(id: $id) @client // 로컬 리졸버에 정의된 toggleTodo를 실행하겠다는 뜻!
  }
`;

function Todo({ id, completed, text }) {
  const [toggleTodo] = useMutation(TOGGLE_TODO, { variables: { id } });
  // 컴포넌트로 뮤테이션이 넘겨지고, 컴포넌트는 UI를 다시 렌더링하게 될 것!
  return (
    <li
      onClick={toggleTodo}
      style=
    >
      {text}
    </li>
  );
}

Managing the cache

writeData

const client = new ApolloClient({
  cache: new InMemoryCache(),
  resolvers: {
    Mutation: {
      updateVisibilityFilter: (_, { visibilityFilter }, { cache }) => {
        const data = { visibilityFilter, __typename: 'Filter' };
        cache.writeData({ data }); // 로컬 리졸버 안에서 캐시 바로 업데이트 치기
      },
    },
  },
};

writeQuery and readQuery

let nextTodoId = 0;

const cache = new InMemoryCache();
cache.writeData({ // 초기 값이 없으면 에러나니까 초기화 해주자
  data: {
    todos: [],
  },
});

const client = new ApolloClient({
  resolvers: {
    Mutation: {
      addTodo: (_, { text }, { cache }) => { // 캐시에 Todo를 써주고 싶다
        const query = gql` // 그러려면 일단 현재 캐시에 있는 Todo들을 가져와야 한다
          query GetTodos {
            todos @client { // 클라이언트에서 가져올거다
              id
              text
              completed
            }
          }
        `;

        const previous = cache.readQuery({ query });
        const newTodo = { id: nextTodoId++, text, completed: false, __typename: 'TodoItem' };
        const data = {
          todos: [...previous.todos, newTodo], // 기존에 있던 Todo들과 합쳐준다
        };

        // you can also do cache.writeData({ data }) here if you prefer
        cache.writeQuery({ query, data }); // 그리고 나서 캐시에 써준다!
        return newTodo;
      },
    },
  },
});

writeFragment and readFragment

const client = new ApolloClient({
  resolvers: {
    Mutation: {
      toggleTodo: (_, variables, { cache }) => {
        const id = `TodoItem:${variables.id}`;
        const fragment = gql`
          fragment completeTodo on TodoItem { // TodoItem 하위로 프래그먼트를 쪼개자
            completed // todos의 하위인 completed만 선택할 수 있다!
          }
        `;
        const todo = cache.readFragment({ fragment, id }); // id를 넘겨서 캐시에서 찾을 수 있다 (cache Key)
        const data = { ...todo, completed: !todo.completed };

        // you can also do cache.writeData({ data, id }) here if you prefer
        cache.writeFragment({ fragment, id, data });
        return null;
      },
    },
  },
});

+) ApolloCache API