Apollo客户端的片段组成:约定和样板

Seb*_*ber 5 apollo reactjs graphql react-apollo

在Apollo应用程序(还有GraphQL / Relay)中,可以选择将数据需求定位在组件上,或者最终自己组装大型GraphQL查询。我们选择将数据需求并置在各个组件上,是因为我们希望长期保持更好的可维护性,因为您无需查看整个组件树或整个页面即可查看所有数据需求,并且可以在本地添加新需求。

我想更好地了解如何使用Apollo客户端编写GraphQL片段。我知道该怎么做,但我想知道如何做得更好。

目前,组成我的片段涉及很多样板,特别是当我的组件只是传递未改变的属性时。

片段声明约定?

首先,让我们看一个简单的组件:

export const User = ({
  user: {
    firstName,
    lastName,
    job,
    email,
    pictureUrl,
    color
  },
  ...props
}) => (
  <UserWrapper {...props}>
    <UserAvatarWrapper>
      <Avatar
        firstName={firstName}
        lastName={lastName}
        color={color}
        src={pictureUrl}
      />
    </UserAvatarWrapper>
    <UserContentWrapper>
      {(firstName || lastName) &&
        <UserName>
          {firstName}
          {" "}
          {lastName}
          {" "}
          {email && <UserEmailInline>{email}</UserEmailInline>}
        </UserName>}
      {job && <UserJob>{job}</UserJob>}
    </UserContentWrapper>
  </UserWrapper>
);
User.fragments = {
  user: gql`
      fragment User on User {
          id
          firstName
          lastName
          pictureUrl: avatar
          job
          color
          email
      }
  `,
};
Run Code Online (Sandbox Code Playgroud)

这里有一些选择。似乎在大多数示例中使用了某种约定,但是该约定在文档中并未明确。

  • 上使用的密钥User.fragments。完全user按照组件的propName命名是否有意义?

  • 片段的名称:按照惯例,人们用组件的名称来命名它,如果有用,请在片段上使用GraphQL类型作为后缀。(这里UserUser可能是过大的后缀)。

我认为在同一应用程序中遵循相同的约定是很好的,这样所有片段声明都是一致的。因此,有经验的人可以帮助我阐明似乎在许多Apollo示例中使用的约定吗?

减少碎片成分样板

现在让我们考虑Relationship遵循我们已建立的约定的组件。

const Relationship = ({ user1, user2 }) => (
  <RelationshipContainer>
      <RelationshipUserContainer>
        <User user={user1} />
      </RelationshipUserContainer/>
      <RelationshipUserContainer>
        <User user={user2} />
      </RelationshipUserContainer/>
  </RelationshipContainer>
);
Relationship.fragments = {
  user1: gql`
      fragment RelationshipUser1User on User {
          ...User
      }
      ${User.fragments.user}
  `,
  user2: gql`
      fragment RelationshipUser2User on User {
          ...User
      }
      ${User.fragments.user}
  `,
};
Run Code Online (Sandbox Code Playgroud)

请注意,这里我声明了两个看起来相同的片段。我认为这是有必要的,因为有2个道具,您不必假定两个道具的数据要求都相同。我们可以轻松地想象一个包含meprops和friendprops 的组件,您将在其中收到有关meprops的更多数据。

这可以正常工作,但是它看起来非常不必要,但它包含很多样板和中间片段。同样,它并不总是很方便,因为从组件用户的角度来看,您必须知道2个片段名称才能使用它。

我试图通过以下简化

Relationship.fragments = {
  user1: User.fragments.user,
  user2: User.fragments.user,
};
Run Code Online (Sandbox Code Playgroud)

这可以工作,但是如果执行此操作,那么片段名称就不再可用了RelationshipUserXUser,而是User意味着它破坏了封装,并且您需要以某种方式知道内部在Relationship使用该User组件。

如果有一天,Relationship组件切换到使用替代表示形式,如UserAlt,这将需要使用Relationships片段从所有组件进行重构,这是我想避免的事情。我认为在这种情况下,修改仅应在Relationship组件中进行。

结论

我想知道用Apollo组成片段的最佳实践,以便使组件保持真正的封装,并且最好不要涉及太多样板。

我已经做对了吗?

如果我真的想编写查询,是否所有这些样板文件都是不可避免的?

Kev*_*ith 3

这样做怎么样:

const userFragment = gql`
  fragment Relationship_user on User {
    ...User_user
  }
  ${User.fragments.user}
`;
Relationship.fragments = {
  user1: userFragment,
  user2: userFragment,
};
Run Code Online (Sandbox Code Playgroud)

除此之外,我建议您如上所示调整片段名称的范围,因为需要某种名称间距,否则您更有可能会两次使用相同的片段名称。

IE

  • User.fragments.user=>User_user
  • Relationship.fragments.user=>Relationship_user