Разрешитель по умолчанию для состояния соединения Apollo не работает (переменные параметра запроса @client)
Пример здесь: https://codesandbox.io/s/j4mo8qpmrw
Документы здесь: https://www.apollographql.com/docs/link/links/state.html
TLDR: это список задач, параметры запроса @client не фильтруют список.
Это запрос, принимающий в качестве параметра $id
const GET_TODOS = gql`
query todos($id: Int!) {
todos(id: $id) @client {
id
text
}
}
`;
Запрос передает переменную туда
<Query query={GET_TODOS} variables={{ id: 1 }}>
/* Code */
</Query>
Но распознаватель по умолчанию не использует этот параметр, вы можете увидеть его в приведенном выше примере codeandbox.io.
Документы говорят, что это должно работать, но я не могу понять, чего мне не хватает. Заранее спасибо!
1 ответ
Для простых случаев использования вы можете полагаться на распознаватель по умолчанию для получения необходимых данных. Однако, чтобы реализовать что-то вроде фильтрации данных в кеше или манипулирования ими (как вы делаете с мутациями), вам нужно написать свой собственный преобразователь. Чтобы выполнить то, что вы пытаетесь сделать, вы можете сделать что-то вроде этого:
export const resolvers = {
Query: {
todos: (obj, args, ctx) => {
const query = gql`
query GetTodos {
todos @client {
id
text
}
}
`
const { todos } = ctx.cache.readQuery({ query })
return todos.filter(todo => todo.id === args.id)
},
},
Mutation: {},
}
РЕДАКТИРОВАТЬ: Каждый тип, который мы определяем, имеет набор полей. Когда мы возвращаем определенный тип (или список типов), каждое поле этого типа будет использовать распознаватель по умолчанию, чтобы попытаться разрешить свое собственное значение (при условии, что это поле было запрошено). Способ работы распознавателя по умолчанию прост - он смотрит на значение родительского (или "корневого") объекта и, если он находит свойство, соответствующее имени поля, он возвращает значение этого свойства. Если свойство не найдено (или не может быть приведено к какому-либо Scalar или Type, которое ожидает поле), оно возвращает null.
Это означает, что мы можем, например, вернуть объект, представляющий одну Todo, и нам не нужно определять преобразователь для его id
или же text
поля, пока объект имеет id
а также text
свойства на нем. Глядя на это по-другому, если мы хотим создать произвольное поле на Todo
называется textWithFoo
мы могли бы оставить значения по умолчанию в кеше и создать резольвер как
(obj, args, ctx) => obj.text + ' and FOO!'
В этом случае распознаватель по умолчанию не принесет нам пользы, поскольку объекты, хранящиеся в кэше, не имеют textWithFoo
свойство, поэтому мы пишем наш собственный распознаватель.
Важно помнить, что такой запрос, как todos
это тоже просто поле (в данном случае это поле типа запроса). Он ведет себя почти так же, как любое другое поле (включая поведение распознавателя по умолчанию). С apollo-link-state
Тем не менее, структура данных, которую вы определяете под defaults
становится родительским или "корневым" значением для ваших запросов.
В вашем примере кода ваш defaults
включить одно свойство (todos
). Поскольку это свойство корневого объекта, мы можем получить его с помощью запроса todos
и по-прежнему получать данные даже без распознавателя. Средство распознавания по умолчанию для todos
поле будет искать в корневом объекте (в данном случае ваш кеш), увидеть свойство с именем todos
и верни это.
С другой стороны, запрос как todo
(единственное) не имеет соответствующего свойства в корне (кеш). Вам нужно написать распознаватель, чтобы он возвращал данные. Точно так же, если вы хотите манипулировать данными перед их возвратом в запросе (с аргументами или без них), вам необходимо включить распознаватель.