使用具有不同片段字段的相同中继根查询的多个 react-router-relay 路由

Posted

技术标签:

【中文标题】使用具有不同片段字段的相同中继根查询的多个 react-router-relay 路由【英文标题】:Multiple react-router-relay routes using same Relay root query with different fragment fields 【发布时间】:2016-01-09 15:45:39 【问题描述】:

我遇到了一个问题,当使用相同的根查询在两个相邻的 react-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 组件仅包含 'name' 字段,则 Relay 不会正确地发出另一个服务器请求,而是用数据填充数组(假设从初始 App 组件服务器请求中缓存)。

难道不应该可以从任一组件获取汽车数组,而无论它们在路线中出现的顺序如何,Relay 都可以获取片段中指定的任何其他数据字段吗?

任何帮助将不胜感激!

【问题讨论】:

【参考方案1】:

(发布为答案,因为我无法在评论中格式化代码。)

您描述的场景听起来非常适合使用嵌套路由:

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

如果您仍然看到具有该结构的空数组,您能否提供指向包含通过网络发送的查询和响应的要点的链接?

【讨论】:

谢谢,这可能是处理对同一源数据类型的查询的首选方法。但是,我暂时将其保持打开状态,我将尝试找到一种方法来处理原始场景而无需嵌套,因为能够查询相同的数据源类型(并包含不同的数据元素)可能很有用在非嵌套的 上。可能路由应该只使用不同的查询对象,但我需要对其进行测试。【参考方案2】:

对于schema.js 文件中的(示例)Car 类型,问题最终无效nodedefinitions。 我最终使用的节点定义是:

 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 请求的额外数据点,导致返回 null 值,从而有效地取消了之前获取的 Car项目。

另外,根定义无效,应该是:

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

node 字段定义错误导致 GraphQL 服务器抱怨无法查询根查询中的“节点”字段。

在这些更正之后,Relay 能够使用不同的数据点查询相同的 Root 字段,而不管在 &lt;Route/&gt; 树中的位置。

虽然嵌套路由可能更适合于相同对象类型的主/详细列表,但有时希望在不相关的 React 组件中包含相同的数据(例如侧边栏、标题等)

【讨论】:

以上是关于使用具有不同片段字段的相同中继根查询的多个 react-router-relay 路由的主要内容,如果未能解决你的问题,请参考以下文章

猫鼬查询具有不同值的相同字段

中继片段传播不起作用

为具有多个定义的查询更新中继存储

将变量传递给现代中继中的片段容器

查询参数(axios 请求)中具有相同键的多个字段?

多个字段解析器使用不同的查询参数解析相同的 REST API