Преобразователь состояния связи Apollo по умолчанию не работает (переменные параметра запроса клиента)

Пример здесь: https://codesandbox.io/s/j4mo8qpmrw

Документы здесь: https://www.apollographql.com/docs/link/links/state.html#default

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 выше.

Документы говорят, что это должно работать, но я не могу понять, чего мне не хватает. Заранее спасибо!


person Webber    schedule 23.05.2018    source источник


Ответы (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.

Это означает, что мы можем, например, вернуть объект, представляющий одну задачу, и нам не нужно определять преобразователь для его полей 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 (единственное число), не имеет соответствующего свойства в корне (кэш). Вам нужно написать преобразователь, чтобы он возвращал данные. Точно так же, если вы хотите манипулировать данными перед их возвратом в запросе (с аргументами или без них), вам необходимо включить преобразователь.

person Daniel Rearden    schedule 29.05.2018
comment
Спасибо, что нашли время опубликовать это, документы немного сбивают с толку. В нем говорится, что преобразователь по умолчанию не требуется, если имена свойств совпадают (что имеет место здесь). evernote.com/l/APeyXGuc1rFApYBdQtLP90j04-q2jddIM3E - person Webber; 29.05.2018
comment
@Webber, пожалуйста, смотрите мое редактирование выше. Надеюсь, это проясняет некоторые вещи - person Daniel Rearden; 29.05.2018
comment
Вы упомянули, что у todo не будет свойства соответствия, но наш запрос — todos (хотя он возвращает только 1 todo). Насколько я понимаю, форма должна полностью совпадать, включая размер массива? - person Webber; 29.05.2018
comment
Я упомянул todo как пример чего-то, что вы не сможете запросить, используя только преобразователь по умолчанию. Размер массива значения не имеет. - person Daniel Rearden; 29.05.2018
comment
Имеет смысл, что todo не будет работать, потому что этого нет в настройках по умолчанию, но в нашем случае мы запрашиваем todos, которые существуют в настройках по умолчанию. - person Webber; 30.05.2018
comment
Я не уверен, что я могу уточнить. Преобразователь по умолчанию для todos возвращает все задачи по умолчанию, как и ожидалось. Резолверы по умолчанию ничего не делают с переданными им аргументами. Если вы хотите использовать аргументы для фильтрации или иного управления данными в кеше, вам нужно будет написать собственный преобразователь, как я показал в ответе выше. - person Daniel Rearden; 30.05.2018