В документации Apollo обсуждается использование cacheRedirects для сообщить Apollo, как получить доступ к данным, которые уже находятся в кеше, из другого запроса.

Это дает пример этого:

В некоторых случаях запрос запрашивает данные, которые уже существуют в клиентском хранилище под другим ключом. Очень распространенный пример этого - когда ваш пользовательский интерфейс имеет представление списка и подробное представление, которые используют одни и те же данные. В представлении списка может выполняться следующий запрос:

запрос ListView {books {id title abstract}}

Когда выбрана конкретная книга, в подробном представлении отображается отдельный элемент с использованием этого запроса:

запрос DetailView {книга (id: $ id) {id title abstract}}

Мы знаем, что данные, скорее всего, уже находятся в кеше клиента, но, поскольку они запрашиваются другим запросом, Apollo Client этого не знает. Чтобы сообщить Apollo Client, где искать данные, мы можем определить настраиваемые преобразователи

Я пытаюсь понять, почему это необходимо для этого примера. Если запрос books возвращает массив типа Book, а запрос book возвращает один объект типа Book, то наверняка в нормализованном кэше уже будут данные для каждого книг (из запроса ListView) на основе имени типа и идентификатора, а запрос DetailView может использовать эту информацию напрямую без какого-либо дополнительного вмешательства. Вместо этого нам велят написать код, который поможет:

const cache = new InMemoryCache({
  cacheRedirects: {
    Query: {
      book: (_, args, { getCacheKey }) =>
        getCacheKey({ __typename: 'Book', id: args.id })
    },
  },
});

В каких именно обстоятельствах ApolloClient не может сам в этом разобраться и почему?

5
tarmes 22 Окт 2018 в 13:36

2 ответа

Лучший ответ

Кажется очевидным и интуитивно понятным, что с учетом запроса, подобного приведенному ниже, мы получаем один объект Book с помощью его свойства id.

query DetailView($id: ID) {
  book(id: $id) {
    id
    title
    abstract
  }
}

Однако в этом примере имя аргумента (id) случайно совпадает с именем свойства, используемого кешем (id). Вне соглашения нет ничего, что говорило бы, что сам аргумент нельзя назвать bookId, bookID или supercalifragilisticexpialidocious. Даже если запрос возвращает тип Book и принимает один или несколько аргументов, Apollo не может определить, какой аргумент на самом деле является идентификатором, который использовался при нормализации кеша. Точно так же, если существуют другие аргументы, они могут иметь или не иметь значения в отношении того, можно ли использовать то, что в настоящее время кэшировано, или нет - для определения этого требуется дополнительная логика.

Другое соображение здесь заключается в том, что помимо факультативной передачи экземпляра IntrospectionFragmentMatcher вашему InMemoryCache, Apollo на самом деле не знает, какова схема запрашиваемой конечной точки. Типы, используемые кешем при нормализации, определяются после получения запроса с помощью свойства __typename. Весь смысл cacheRedirects состоит в том, чтобы предотвратить запуск запроса, если элемент или элементы уже находятся в кэше. Однако, учитывая конкретный запрос, Apollo не имеет возможности узнать, вернет ли он определенный тип, до тех пор, пока этот запрос не вернется. cacheRedirects предоставляет способ сказать, что «этот запрос вернет этот конкретный тип», даже не инициируя запрос.

2
Daniel Rearden 22 Окт 2018 в 13:03

Просто запоздалая мысль: это по своей сути связано с дизайном GraphQL. В GraphQL преобразователь book(id) может интерпретировать id как угодно. Это просто вызов функции с одним параметром, который возвращает экземпляр типа Book.

GraphQL вообще ничего не говорит об идентификаторах. Он распознает только __typename как особенный.

Только Relay и, в некоторой степени, Apollo добавят понятие идентификаторов объектов позже. Однако они используют немного другой подход: Relay превращает вашу схему GraphQL в более жесткую формальную структуру.

Существует даже дополнительная сложность (упомянутая в другом ответе), связанная с тем, что схема недоступна для клиента (так что клиент даже не знает, что book вернет Book без запроса). Это снова следует из спецификации GraphQL.

0
Nikola Mihajlović 26 Окт 2018 в 20:16
52927310