Что использует Relay, чтобы решить, какие outputFields включить в ответ на мутацию?

Я создаю свое первое приложение React/Relay, изменяя пример TODO. Я дошел до того, что добавляю свою собственную мутацию для объекта Distributor, у которого есть параметр bookCount. Мутация называется AddBook и просто увеличивает количество книг на 1. В этот момент мутация выполняется без ошибок, оптимистично правильно увеличивает bookCount на 1, но затем отменяет изменение модели, когда получает ответ от сервера. Я считаю, что это связано с тем, что ответ сервера таинственным образом не содержит ни одного из указанных мной полей вывода.

Вот моя мутация:

var GraphQLAddBookMutation = mutationWithClientMutationId({
  name: 'AddBook',
  inputFields: {
  },
  outputFields: {
    distributor: {
      type: GraphQlDistributor,
      resolve: () => getDistributor(),
    },
  },
  mutateAndGetPayload: () => {
    console.log("Trying to mutate.");
    addBook();
    return {};
  },
});

Он содержит поле «дистрибьютор» в outputFields, но данные «дистрибьютора» не включены в ответ graphql.

Ответ графа:

{
  "data": {
  "addBook": {
    "clientMutationId": "0"
    }
  }
}

Я проверил, что функция mutateAndGetPayload вызывается, но функция разрешения дистрибьютора НЕ вызывается.

Я ожидал, что каждое поле в outputFields будет включено в ответ graphql, и каждая функция разрешения в outputFields будет вызываться для заполнения соответствующих параметров в ответе, но это не так.

Меня это особенно сбивает с толку, потому что сгенерированный schema.json ДЕЙСТВИТЕЛЬНО включает любые поля outputField, которые я указываю в AddBookPayload:

{
      "kind": "OBJECT",
      "name": "AddBookPayload",
      "description": null,
      "fields": [
        {
          "name": "distributor",
          "description": null,
          "args": [],
          "type": {
            "kind": "OBJECT",
            "name": "Distributor",
            "ofType": null
          },
          "isDeprecated": false,
          "deprecationReason": null
        },
        {
          "name": "clientMutationId",
          "description": null,
          "args": [],
          "type": {
            "kind": "NON_NULL",
            "name": null,
            "ofType": {
              "kind": "SCALAR",
              "name": "String",
              "ofType": null
            }
          },
          "isDeprecated": false,
          "deprecationReason": null
        }
      ],
      "inputFields": null,
      "interfaces": [],
      "enumValues": null,
      "possibleTypes": null
    },

person OverclockedTim    schedule 16.09.2015    source источник


Ответы (1)


Наконец-то я смог сам найти ответ на этот вопрос и ошибку в коде, поэтому я включу его сюда для всех, кто сталкивается с той же проблемой.

Первое, что нужно понять, это связь между FatQuery и selectionSet. FatQuery используется (веб) клиентом, чтобы понять, какие возможные вещи могут измениться после выполнения рассматриваемой мутации. Клиент будет анализировать толстый запрос и собственное внутреннее состояние, чтобы увидеть, есть ли какие-либо совпадения. Если FatQuery указывает, что ничто в мутации не изменит ничего, что в данный момент волнует клиента (существует в его внутреннем хранилище), тогда клиент будет использовать GraphQL, чтобы указать, что он не хочет, чтобы какие-либо данные возвращались (если вы используете все библиотеки javascript по умолчанию, это будет преобразовано из без возврата данных в только идентификатор мутации клиента). Это достигается с помощью selectionSet. Вы можете просмотреть запрошенный набор выбора в GraphQL, просмотрев сетевой вызов сервера в окне браузера. В моем случае этот набор выбора был пуст, что было моей первой подсказкой.

Короче говоря, outputFields, включенные в ответ на мутацию, представляют собой пересечение всех перечисленных outputFields из внутреннего состояния клиента FatQuery и GraphQL.

P.S. Есть еще один важный фактор, который здесь играет роль, а именно указание идентификаторов, которые можно изменить. Каждый бит данных в GraphQL должен иметь глобально уникальный идентификатор. В примере приложения TODO этот глобально уникальный идентификатор создается как комбинация имени рассматриваемого типа и переменной-члена 'id' рассматриваемого типа. В моем случае, поскольку у меня не было переменной-члена id, возникла некоторая путаница. Итак, если вы, как и я, экспериментируете с использованием приложения TODO в качестве основы для своих экспериментов, убедитесь, что любой создаваемый вами тип имеет уникальную для типа переменную-член с именем 'id'.

person OverclockedTim    schedule 17.09.2015
comment
Спасибо, это мне очень помогло. Я хотел, чтобы на большее количество вопросов, связанных с реле, были даны ответы, а не оставались сиротами. - person Christine; 27.01.2016