【问题标题】:Organization structure for fragment composition in large react-apollo apps大型 react-apollo 应用程序中片段组合的组织结构
【发布时间】:2018-06-09 13:47:42
【问题描述】:

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

我尝试创建一个全局高级 graphql 目录,我的所有 queries/mutations.graphql 文件都位于该目录中,导入位于我的应用程序中的所有相关片段文件,然后直接导入这些文件,但这可能会变得乏味并且不会t 遵循父查询包含子片段的父/子主题。同样在大型项目中,您最终会在导入时遍历长文件路径。

我也尝试过在全局 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 的片段组合。

对于这类事情有首选方法或最佳实践吗?

【问题讨论】:

    标签: reactjs graphql apollo apollo-client react-apollo


    【解决方案1】:

    结构化查询

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

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

    结构化突变

    当涉及到突变时,通常很难为它们找到合适的位置。突变需要在组件树很远的事件上调用,并且经常在应用程序的多个状态中更改应用程序的状态。在这种情况下,您希望调用者不知道数据消费者。使用片段似乎是一个简单的答案。突变将只包括为特定类型定义的所有片段。虽然突变现在不需要知道需要哪些字段,但它需要知道 需要类型上的字段。我想指出两种略有不同的方法,您可以使用它们来作为设计的基础。

    全局突变:中继方法

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

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

    很遗憾,我们无法回答一个问题:我们应该走多远?我是否需要喜欢 cmets 的人的姓名,还是组件只显示喜欢的次数?

    查询容器中的突变

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

    总结

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

    让我知道您对 cme​​ts 的看法!

    【讨论】:

    • 很好的答案,谢谢,让我朝着正确的方向思考!
    猜你喜欢
    • 2011-12-21
    • 1970-01-01
    • 1970-01-01
    • 2016-09-21
    • 1970-01-01
    • 2015-01-20
    • 2019-02-08
    • 1970-01-01
    • 2016-11-15
    相关资源
    最近更新 更多