首页 文章

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

提问于
浏览
3

我正在使用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 回答

  • 3

    构造查询

    如何构建代码始终是个人品味的问题,但我认为查询和组件的搭配是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类型将传递给查询容器,该查询容器将 CommentsPage 包装在查询和变异中 .

    摘要

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

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

相关问题