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

标签 reactjs graphql apollo apollo-client react-apollo

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

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

我还尝试仅创建与组件文件相对应的全局 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 中的片段组合。

对于此类事情是否有首选方法或最佳实践?

最佳答案

构建查询

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

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

构建突变

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

全局突变:中继方法

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

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

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

查询容器中的突变

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

摘要

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

请在评论中告诉我你的想法!

关于reactjs - 大型react-apollo应用程序中片段组合的组织结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48017187/

相关文章:

reactjs - 为什么重新运行只使用react-hooks-testing-library更新一次props?

javascript - 使用 React.forwardRef 与自定义 ref prop 的值(value)

node.js - 类型错误 : Cannot read property 'belongsTo' of undefined

django - Apollo-client 在向服务器发送突变时返回 "400 (Bad Request) Error"

javascript - 当我尝试在组件中使用 antd 的表单时,无法读取未定义的属性 'getFieldDecorator'

javascript - 使用 React Hooks 进行动态媒体查询

reactjs - 使用 TypeScript react Apollo useQuery 钩子(Hook)

javascript - Apollo服务器超时消息

graphql - graphql 类型定义中的日期和 Json

graphql - 使用 NEXT.js 和 Apollo 客户端 2 配置订阅