В Relay, какую роль играет интерфейс node и глобальная спецификация ID?

Я начал с relay-starter-kit, а также проработал путь через документацию Relay и GraphQL. Но есть немало областей, которые необъяснимы и таинственны.

Серьезно я читал много документов по всему миру обо всех этих вещах, но не смог найти удовлетворительных объяснений по следующим вопросам:

Для чего это? Я помещаю журнал, но он даже не вызван вообще:

var {nodeInterface, nodeField} = nodeDefinitions(
  (globalId) => {
    var {type, id} = fromGlobalId(globalId);
    if (type === 'User') {
      return getUser(id);
    } else if (type === 'Widget') {
      return getWidget(id);
    } else {
      return null;
    }
  },
  (obj) => {
    if (obj instanceof User) {
      return userType;
    } else if (obj instanceof Widget) {
      return widgetType;
    } else {
      return null;
    }
  }
);

И каков фактический эффект этого:

interfaces: [nodeInterface],

Возможно, это связано с тем, что здесь делает поле node:

var queryType = new GraphQLObjectType({
  name: 'Query',
  fields: () => ({
    node: nodeField,
    // Add your own root fields here
    viewer: {
      type: userType,
      resolve: () => getViewer(),
    },
  }),
});

А что такое волшебство вокруг поля id? Что такое globalIdField для?

У меня есть id в моей базе данных и я думал, что могу использовать его в своих объектах GraphQL:

Вместо:

id: globalIdField('User'),

Я хочу использовать идентификатор моей базы данных:

id: {
  type: GraphQLID,
  description: 'The identifier'
},

Но если я это сделаю, я получаю сообщение об ошибке в браузере, говоря RelayQueryWriter: Could not find a type name for record '1'.

Я могу избавиться от этой ошибки, добавив __typename в мои контейнеры компонентов Relay Query, но это кажется неправильным.

Было бы здорово, если бы вы могли дать более глубокие внутренности и лучшее объяснение здесь и улучшить официальную документацию.

Спасибо

Ответ 1

Корневое поле Node в сочетании с глобально уникальными идентификаторами вступает в игру, когда Relay необходимо восстановить объект. Повторный вызов происходит, когда вы вызываете this.props.relay.forceFetch() или когда вы добавляете поля в запрос для объекта, глобальный идентификатор которого известен, потому что он уже частично извлечен.

В подобных случаях Relay будет коротко закоротить регулярный запрос и выполнить запрос для объекта (ов) напрямую, используя его глобальный идентификатор и корневой вызов Node.

Пример:

Предположим, что $showComments был false, когда этот запрос был сначала разрешен.

query {
  viewer {
    stories(first: 10) {
      edges {
        node {
          id,
          comments(first: 10) @include(if: $showComments) { 
            author, 
            commentText 
          }
          text,
        }
      }
    }
  }
}

Это вызвало выборку для id и text для некоторого количества историй, чьи идентификаторы теперь известны.

Представьте, что в какое-то время переменная $showComments стала true. Реле будет восстанавливать только нужные ему данные с помощью корневого поля Node.

query {
  node(id: "ABC123") { 
    fragment on Story { comments(first: 10) { author, commentText } }
  }
  node(id: "DEF456") { 
    fragment on Story { comments(first: 10) { author, commentText } }
  }
  node(id: "GHI789") { 
    fragment on Story { comments(first: 10) { author, commentText } }
  }
  ...
}

Это зависит от нескольких частей:

  • Каждый объект должен иметь глобально уникальный идентификатор или быть идентифицирован парой типа/идентификатора (помощник globalIdField делает это и создает строку с кодировкой base64).
  • Сервер должен знать, как разрешить объект из уникального глобального идентификатора, и наоборот. Это то, что для nodeDefinitions для.
  • Любой объект, который надеется быть повторно подключенным с помощью этой системы, должен реализовать nodeInterface.

Смотрите также: https://facebook.github.io/relay/docs/graphql-object-identification.html#content