我可以从 Relay 查询结果中提取深度嵌套的节点吗?

Posted

技术标签:

【中文标题】我可以从 Relay 查询结果中提取深度嵌套的节点吗?【英文标题】:Can I pull deeply-nested nodes from a Relay query result? 【发布时间】:2017-05-22 06:10:32 【问题描述】:

我的目标是将同一个 Relay fragment 中的多个嵌套同级 arraysedges 组合成一个 render 调用。

后端数据通过Relay 容器传递(也使用react-router-relay)。

我有一个组件层次结构,它显示来自多个不同Users 的多个Tags。***查询如下所示:

getUserGroup(id: 'abc') 
  users 
    edges  // array of arrays objects with nested arrays
      node 
        Tags 
          edges  // array of objects with target items
            node 
              tagName // target item
              id
            
          
        
      
    
  

这会导致这样的结果(完全扁平化的形式):

  results = [['tagname1', 'tagname2'], [tagname3, tagname4]]

目前,我在自己的Component 中呈现每个node Type 的层次结构,即Tagmenu -> UserTagGroup -> TagItems(代码在这篇文章的底部)。

这会将所有标签按User 分组,最终呈现如下列表:

User 1:
  - Tag 1
  - Tag 2
User 2:
  - Tag 3
  - Tag 4

我想要实现的是render,其中所有Users'标签在第二层混合在一起,即像TagMenu这样的层次结构@ -> TagItems,以呈现:

User Tags
  - Tag 1
  ...
  - Tag 4

到目前为止,我能管理的唯一方法是手动从*** Relay 容器结果中提取所有数组并将其与类似这样的内容(伪代码)组合:

for each array in users.edges:
  for each array in node.Tags.edges:
    return node.tagName

这似乎不正确,原因有两个:

    打包到 render() 函数中有点多, 不清楚是否可以to protect against null refs with default props in Relay

...但这显然是可行的。

我的问题是:Relay 的方法是什么?考虑到库如何自然地导致组件组合,我无法想象在更高级别拉深嵌套的结果并手动改组它们是最佳的。这是我的组件:

// TagsMenu component, top level
class TagsMenu extends Component 
  render() 
    return (
      <div>
        
          this.props.userGroup.users.edges.map(u => 
            return <UserTagGroup user=u.node />
          )
        
      </div>
    )
  


fragment on UserGroup 
  users(first: 1000) 
    edges 
      node 
        $UserTagGroup.getFragment('user')
      
    
  



// UserTagGroup, second component
class UserTagGroup extends Component 
  render() 
    return (
      <div>
        <h4>User:  this.props.user.id</h4>
        
          this.props.user.Tags.edges.map(t => 
            return <TagMenuItem tag=t.node />
          )
        
      </div>
    )
  

fragment on User 
  id
  listingTags(first: 1000) 
    edges 
      node 
        $TagMenuItem.getFragment('tag')
      
    
  



// TagMenuItem, bottom level component. Renders 1 Tag.
class TagMenuItem extends Component 
  render() 
    return (
      <div>
        this.props.tag.tagName
      </div>
    )
  

fragment on Tag 
  tagName
  id

【问题讨论】:

【参考方案1】:

您一直在描述的内容 - “手动从*** Relay 容器中提取和组合所有数组” - 不过看起来确实是可行的方法。

如果问题出在render()方法中有这个功能,我建议你结合使用状态和方法componentWillReceiveProps()。目标是仅在 this.props.users 真正改变时重新计算扁平化列表。

沿着这些路线的东西:

class MyRootContainer extends Component 

  constructor(props) 
    super(props);

    this.state = 
      flattenedList: this.computeFlattenedListFromProps(this.props),
    ;
  

  componentWillReceiveProps(props) 
    if (this.props.users !== props.users) 
      this.setState(
        flattenedList: this.computeFlattenedListFromProps(props),
      );
    
  

  computeFlattenedListFromProps(props) 
    // Compute and return flattened list
  

  render() 
    ...
  

【讨论】:

以上是关于我可以从 Relay 查询结果中提取深度嵌套的节点吗?的主要内容,如果未能解决你的问题,请参考以下文章

Relay.js 中的根查询创建和删除

无法从 Github 的 GraphQL 渲染嵌套道具

从 JSON 中提取深度嵌套的值

MongoDB Mongoose 聚合查询深度嵌套数组删除空结果并填充引用

中继编译器无法在 Typescript 中提取和使用 graphql 查询

从 Firebase 中的嵌套查询填充回收站视图