Моя проблема:
Я новичок в GraphQL, и я разрабатываю свое первое приложение с полным стеком, используя сервер и клиент Apollo, это простой блог.
На стороне клиента я использую один и тот же запрос на двух разных страницах, но с разными переменными. Запросы запрашивают статью в блоге по идентификатору или слагу, в зависимости от страницы, которую я использую. Таким образом, результат тот же, изменяются только переменные запросов.
Когда я использую запрос на одной странице, я думал, что запрос не будет работать на второй странице из-за кеша Apollo. Но это не то, что происходит. Запрос запускается снова во второй и, конечно же, возвращает мне тот же результат, что и на другой странице.
Почему в этом случае Apollo не использует кеш?
Вот код, который я использую:
На стороне сервера у меня есть довольно простой запрос для получения статьи из блога, который можно получить по идентификатору или слагу:
type Query {
...
article(id: ID, slug: String): Article
...
}
На стороне клиента я запрашиваю статью по слагу, если статья опубликована, или по идентификатору, если это еще черновик.
Запрос по слагу:
<Query
query = {article}
variables = {{ slug }}
fetchPolicy = "cache-and-network"
>
{({ loading, error, data }) => {
return (
<Article
loading = {loading}
article = {data && data.article}
/>
);
}}
</Query>
Запрос по идентификатору такой же, за исключением параметра переменных, в котором используется идентификатор:
<Query
query = {article}
variables = {{ id }}
>
{({ loading, error, data }) => {
return (
<EditArticle loading = {loading} article = {data && data.article} />
);
}}
</Query>
Как видите, оба используют одну и ту же конечную точку GraphQL, и результат одинаков. Но кеш не используется.


Apollo предполагает, что ваши резолверы чистые (у них нет побочных эффектов и в основном они возвращают тот же результат при тех же входных данных / аргументах). Это уже многое предположить. Представьте себе преобразователь, который возвращает случайное число или самый новый комментарий на новостном веб-сайте. Оба не всегда возвращали один и тот же результат при одном и том же вводе. С другой стороны, Apollo не делает - и почти не может делать - предположений о реализации вашего распознавателя. Пока в вашей голове реализация распознавателя статей очевидна (если присутствует id, верните статью с этим идентификатором, если есть slug, верните статью с этим слагом), от компьютерной программы сложно догадаться.
Я ответил аналогичный вопрос недавно. Чтобы предотвратить запуск второго запроса, вы должны реализовать перенаправление кеша. Обратной стороной является то, что вы должны синхронизировать перенаправления кеша на клиенте и резолверы на сервере.
у вас есть пример перенаправления кеша с моими запросами? Вроде хорошо работает с ID, но я не могу понять, как заставить его работать со слагами ...
Это действительно кажется довольно сложным. Я подумал, что будет простой способ получить все элементы с определенным именем типа, и оттуда вы могли бы использовать Array.prototype.find для поиска нужного элемента. Может быть, вы могли бы попытаться спросить их на слабина
Я столкнулся с той же проблемой. По сути, я ожидал, что поиск в кеше просто не удастся, когда он попытается найти только "slug", и меня это устроило, но вместо этого он не смог сгенерировать правильный результат поиска, и результат "null" будет возвращен как ответ на запрос, как если бы это был успешный ответ на запрос. Ой.
Чтобы избежать побочных эффектов, я просто буду использовать отдельный запрос graphQL, который принимает слаг вместо идентификатора. У этого есть несколько других преимуществ, например, я могу использовать поле как «обязательное» в их соответствующих запросах. Главное, что он делает запрос на основе идентификатора более детерминированным и, следовательно, более совместимым с кешированием.
type Query {
...
article(id: ID!): Article
articleBySlug(slug: String!): Article
...
}
Еще лучше была бы возможность поиска в кэше с использованием вашего значения "slug" для получения соответствующего результата, но, похоже, это пока не поддерживается без использования "slug" как части самого идентификатора кеша.
Вы правы, я только что понял пару часов назад, что Apollo ничего не знает о моих распознавателях на стороне сервера и не может знать, что запрос вернет тот же результат. Я, вероятно, предположил это, потому что я исхожу из Meteor, где клиент и сервер «связаны» через DDP. Я не знал о перенаправлении кеша (еще не читал документ до этой части), поэтому я использовал функцию
client.writeQuery(), чтобы записать результат второго запроса в кеш, когда я получил первый. Я думаю, это очень похоже на перенаправление кеша.