Несколько маршрутов реакции-маршрутизатора-ретранслятора с использованием одного корневого запроса ретрансляции с различными полями фрагмента

Я сталкиваюсь с проблемой, когда при запросе данных в двух смежных компонентах маршрута relay-router-relay, использующих тот же корневой запрос, запрос сервера graphql во втором компоненте маршрута делает недействительными данные, ранее полученные из первого.

В качестве примера:

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

Мой schema.js содержит следующие определения для типа просмотра (пользователя) и корня:

var GraphQLUser = new GraphQLObjectType({
   name: 'User',
   isTypeOf: function(obj) { return obj instanceof User },
   fields: function() {
      return {
         id: GraphQLRelay.globalIdField('User'),
         //Fields to expose to app, e.g. cars
         cars: {
            type: GraphQLRelay.connectionDefinitions({
               name: 'Car', nodeType: carType
            }).connectionType,
            args: GraphQLRelay.connectionArgs,
            resolve: function(user, args) {
               return
                 GraphQLRelay.connectionFromPromisedArray(getCars(), args)
            },
        },
     }
 },
 interfaces: [nodeDefinitions.nodeInterface],
});

И корень:

var Root = new GraphQLObjectType({
   name: 'Root',
   fields: {
      viewer: {
         type: GraphQLUser,
         resolve: (root, {} ) => getUser()
    },
    node: nodeDefinitions.nodeField
});

Теперь в точке входа приложения main.jsx я определяю следующие маршруты:

ReactDOM.render(
   <Router createElement={ReactRouterRelay.createElement}>
      <Route path="/" component={App} queries={ViewerQueries} />
      <Route path="/cars" component={AllCars} queries={ViewerQueries} />
  </Router>,
  document.getElementById('ReactContainer'));

с ViewerQueries.js, содержащим:

export default {
   viewer: () => Relay.QL`query { viewer }`,
};

Теперь, если App Компонент включает следующий фрагмент graphql:

exports.Component = Relay.createContainer(App, {
   initialVariables: {
      limit: 10
   },
   fragments: {
      viewer: () => Relay.QL`
         fragment on User {
         cars (first: $limit) {
            edges {
              node {
                 name,
              }
            }
          }
       }`,
   },
 })

И AllCars Компонент включает в себя следующее:

exports.Component = Relay.createContainer(AllCars, {
   initialVariables: {limit: 10},
   fragments: {
      viewer: () => Relay.QL`
         fragment on User {
            cars (first: $limit) {
               edges {
                  node {
                     name,
                     type
                  }
               }
            }
        }`,
     },
  })

получается, что при рендеринге компонента App по пути '/' массив машин возвращается без проблем. Тем не менее, после отображения пути "/cars", результирующий массив в this.props.viewer.cars становится пустым. Кроме того, возврат к пути '/' для повторного рендеринга компонента App теперь также возвращает пустой массив.

На бэкэнде, похоже, компонент AllCars вызывает дополнительный POST /graphql 200 277.369 ms - 94 поездка на сервер за новым type указано во фрагменте. Если компонент AllCars содержит только поле "имя", Relay правильно не выполняет другой запрос к серверу, а вместо этого заполняет массив данными (предположительно, кешируется из первоначального запроса к серверу компонента App).

Разве нельзя получить массив автомобилей из любого компонента, когда Relay получит какие-либо дополнительные поля данных, указанные во фрагментах, независимо от их порядка на маршрутах?

Любая помощь будет принята с благодарностью!

2 ответа

Решение

Проблема оказалась недействительной nodedefinitions для (пример) Car введите в schema.js файл. Определения узлов, которые я в итоге использовал:

 var nodeDefinitions = GraphQLRelay.nodeDefinitions(function(globalId) {
   var idInfo = GraphQLRelay.fromGlobalId(globalId)
     if (idInfo.type == 'Car') {
        return getCarById(idInfo.id)
     } else if ...
       // Other types here
     }
    return null
 });

Возвращенная функция getCarById не правильно разрешила объект Car, и сервер GraphQL не смог получить дополнительные точки данных, запрошенные Relay, в результате чего вместо этого было возвращено нулевое значение, что фактически сводило на нет ранее выбранные объекты. Car Предметы.

Кроме того, определение Root недопустимо и должно быть:

var Root = new GraphQLObjectType({
   name: 'Root',
   fields: {
      viewer: {
         type: GraphQLUser,
         resolve: (root, {} ) => getUser()
      },
      node: nodeDefinitions.nodeField
   }
});

Неуместный node из-за определения поля сервер GraphQL пожаловался на невозможность запросить поле "узел" в корневом запросе.

После этих исправлений Relay может запрашивать одно и то же корневое поле, используя разные точки данных, независимо от размещения в <Route/> дерево.

Хотя вложенные маршруты, вероятно, предпочтительнее для основных / подробных списков одного и того же типа объекта, иногда желательно включать одни и те же данные в несвязанные компоненты React (например, боковые панели, заголовки и т. Д.)

(Отправка как ответ, потому что я не могу отформатировать код в комментарии.)

Описанный вами сценарий хорошо подходит для использования вложенных маршрутов:

ReactDOM.render(
  <Router createElement={ReactRouterRelay.createElement}>
    <Route path="/" component={App} queries={ViewerQueries}>
      <Route path="/cars" component={AllCars} queries={ViewerQueries} />
    </Route>
  </Router>,
  document.getElementById('ReactContainer')
);

Если вы все еще видите пустые массивы с этой структурой, можете ли вы предоставить ссылку на список, содержащий запросы и ответы, отправленные по сети?

Другие вопросы по тегам