大型react-apollo应用程序中片段组合的组织结构

时间:2017-12-29 03:54:39

标签: reactjs graphql apollo react-apollo

我正在使用Apollo Client和React,我正在寻找一种策略来保持我的组件和组件数据要求的位置,以便父/兄弟/子组件可以访问它们可能需要查询和突变。我希望能够轻松更新数据需求,这些数据需求将更新某些父组件查询的字段或父/兄弟/子项中的变异返回的字段,以便准确更新我的Apollo缓存。

我已经尝试创建一个全局高级graphql目录,其中包含所有查询/ mutation.graphql文件,#importing遍布我的应用程序的所有相关片段文件,然后直接导入它们,但这可能会变得单调乏味不遵循父/子主题,其中父查询包括子片段。此外,在大型项目中,您最终会在导入时遍历长文件路径。

我还尝试过在全局graphql目录中创建与组件文件相对应的片段文件,但是这并没有给我“我正在寻找的”组件/数据要求“主机托管。

这有效:

class CommentListItem extends Component {
  static fragments = {
    comment: gql`
      #...
    `,
  }
}
class CommentList extends Component {
  static fragments = {
    comment: gql`
      #...
      ${CommentListItem.fragments.comment}
    `,
  }
}
class CommentsPage extends Component {
  static fragments = {
    comment: gql`
      #...
      ${CommentList.fragments.comment}
    `,
  }
}
graphql(gql`
  query Comments {
    comments {
      ...CommentsListItemComment
    }
  }
  ${CommentsPage.fragments.comment}
`)

但是,如果我想在CommentsPage的后代中进行变异,我就无法从CommentsPage.fragments.comment引用片段组成。

对于这类事物,是否有首选方法或最佳做法?

1 个答案:

答案 0 :(得分:6)

构建查询

如何构建代码始终是个人品味的问题,但我认为查询和组件的搭配是GraphQL的一大优势。

对于查询,我从Relay Modern中获得了很多灵感,解决方案看起来非常接近您在代码中描述的内容。现在,随着项目变得越来越大,我们想要为查询生成Flow类型定义,将它们放在组件文件旁边的单独文件中也是一种选择。这与CSS-modules非常相似。

构建突变

当涉及到突变时,为它们找到一个好地方往往要困难得多。需要在远离组件树的事件上调用突变,并且经常在应用程序的多个状态中更改应用程序的状态。在这种情况下,您希望调用者不知道数据使用者。使用片段似乎是一个简单的答案。突变将仅包括为特定类型定义的所有片段。虽然突变现在不需要知道哪些字段是必需的,但它需要知道需要该类型的字段。我想指出两种稍微不同的方法,您可以使用这些方法来设计。

全球突变:接力方法

在Relay Modern Mutations are basically global operations中,可以由任何组件触发。这种方法并不坏,因为大多数突变只写一次,并且由于变量非常可重复使用。它们在一个全局状态下运行,并不关心哪个UI部分消耗更新。定义变异结果时,通常应查询可能由变异更改的属性,而不是其他组件(通过片段)所需的所有属性。例如。变异likeComment(id: ID!)可能应该在评论中查询likeCountlikes字段,如果任何组件完全使用该字段或Comment上组件需要哪些其他字段,则无关紧要。当您必须更新其他查询或字段时,此方法会变得更加困难。变异createComment(comment: CreateCommentInput)可能想要写入根查询对象的comments字段。这是节点和边缘的Relays结构派上用场的地方。您可以详细了解中继更新here

# A reusable likeComment mutation
mutation likeComment($id: ID!) {
  likeComment(id: $id) {
    comment {
      id
      likeCount
      likes {
        id
        liker {
          id
          name
        }
      }
    }
  }
}

不幸的是我们无法回答一个问题:我们应该走多远?我是否需要喜欢评论的人的名字,或者组件是否只显示了许多喜欢的内容?

查询容器中的突变

并非所有GraphQL API都采用Relay方式构建。此外,Apollo将突变绑定到商店,类似于Redux动作创建者。我目前的方法是在与查询相同的级别上进行突变,然后将它们传递下去。通过这种方式,您可以访问子项的片段,并在需要时在突变中使用它们。在您的示例中,CommentListItem组件可能会显示类似按钮。它将为数据依赖关系定义一个片段,根据片段和函数prop类型likeComment: (id: string) => Promise<any>定义prop类型。此prop类型将传递给查询容器,该容器将CommentsPage包装在查询和变异中。

摘要

您可以将这两种方法与Apollo一起使用。全局mutations文件夹可以包含可在任何地方使用的突变。然后,您可以直接将突变绑定到需要它们的组件。一个好处是,例如,在likeComment示例中,变量id可以直接从组件props派生而来,不需要在组件本身内绑定。或者,您可以从查询组件中传递突变。这为您提供了更广泛的数据使用者概述。在CommentsPage中,可以更容易地确定突变完成时需要更新的内容。

让我知道你在评论中的想法!