与 Apollo 客户端的片段组合:约定和样板
Fragment composition with Apollo client: convention and boilerplate
在 Apollo 应用程序中(还有 GraphQL/Relay),可以选择将数据需求并置到组件中,或者最终 assemble 自己进行大型 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
}
`,
};
这里有一些选择。似乎在大多数示例中都使用了某种约定,但该约定在文档中并不明确。
User.fragments
上使用的密钥。将其命名为与组件的 propName user
完全相同是否有意义?
片段的名称:似乎按照惯例人们用组件的名称来命名它,如果有用的话,在它们后面加上片段所在的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}
`,
};
请注意,我在这里声明了 2 个看起来相同的片段。我认为这是必要的,因为有 2 个道具,你不应该假设两个道具的数据要求是相同的。我们可以很容易地想象一个具有 me
props 和 friend
props 的组件,您将在其中接收更多关于 me
props 的数据。
这工作正常,但它有很多样板和中间片段,看起来很不必要。此外,它并不总是很方便,因为从组件用户的角度来看,您必须知道 2 个片段名称才能使用它。
我试图用以下方法简化它
Relationship.fragments = {
user1: User.fragments.user,
user2: User.fragments.user,
};
这可行,但如果您这样做,片段名称将不再是 RelationshipUserXUser
,而是 User
,这意味着它破坏了封装,您需要注意在内部,Relationship
组件正在使用 User
组件。
如果有一天,Relationship
组件切换到使用替代表示,如 UserAlt
,这将需要使用关系片段重构所有组件,这是我想避免的事情.我认为在这种情况下,修改应该只发生在 Relationship
组件中。
结论
我想知道使用 Apollo 组合片段的最佳实践,以便组件保持真正的封装,最好不要涉及太多样板文件。
我已经在做正确的事了吗?
如果我真的想编写查询,所有这些样板都是不可避免的吗?
这样怎么样:
const userFragment = gql`
fragment Relationship_user on User {
...User_user
}
${User.fragments.user}
`;
Relationship.fragments = {
user1: userFragment,
user2: userFragment,
};
除此之外,我建议您如上所示限定片段名称的范围,因为需要某种名称间距,否则您更有可能 运行 使用相同的片段名称两次。
即
User.fragments.user
=> User_user
Relationship.fragments.user
=> Relationship_user
在 Apollo 应用程序中(还有 GraphQL/Relay),可以选择将数据需求并置到组件中,或者最终 assemble 自己进行大型 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
}
`,
};
这里有一些选择。似乎在大多数示例中都使用了某种约定,但该约定在文档中并不明确。
User.fragments
上使用的密钥。将其命名为与组件的 propNameuser
完全相同是否有意义?片段的名称:似乎按照惯例人们用组件的名称来命名它,如果有用的话,在它们后面加上片段所在的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}
`,
};
请注意,我在这里声明了 2 个看起来相同的片段。我认为这是必要的,因为有 2 个道具,你不应该假设两个道具的数据要求是相同的。我们可以很容易地想象一个具有 me
props 和 friend
props 的组件,您将在其中接收更多关于 me
props 的数据。
这工作正常,但它有很多样板和中间片段,看起来很不必要。此外,它并不总是很方便,因为从组件用户的角度来看,您必须知道 2 个片段名称才能使用它。
我试图用以下方法简化它
Relationship.fragments = {
user1: User.fragments.user,
user2: User.fragments.user,
};
这可行,但如果您这样做,片段名称将不再是 RelationshipUserXUser
,而是 User
,这意味着它破坏了封装,您需要注意在内部,Relationship
组件正在使用 User
组件。
如果有一天,Relationship
组件切换到使用替代表示,如 UserAlt
,这将需要使用关系片段重构所有组件,这是我想避免的事情.我认为在这种情况下,修改应该只发生在 Relationship
组件中。
结论
我想知道使用 Apollo 组合片段的最佳实践,以便组件保持真正的封装,最好不要涉及太多样板文件。
我已经在做正确的事了吗?
如果我真的想编写查询,所有这些样板都是不可避免的吗?
这样怎么样:
const userFragment = gql`
fragment Relationship_user on User {
...User_user
}
${User.fragments.user}
`;
Relationship.fragments = {
user1: userFragment,
user2: userFragment,
};
除此之外,我建议您如上所示限定片段名称的范围,因为需要某种名称间距,否则您更有可能 运行 使用相同的片段名称两次。
即
User.fragments.user
=>User_user
Relationship.fragments.user
=>Relationship_user