在React/Relay/Typescript中重用组件的最佳实践是什么?



我正在用React, Relay(实验性)和Typescript制作一个web应用程序,我在不同片段中重用具有类似数据/道具的组件时遇到了一些问题。

假设我有以下中继查询和主应用组件:

const query = graphql`
query AppQuery {
currentUser {
...HomePage_currentUser
...ProfilePage_currentUser
}
}
`;
export default function App(): JSX.Element {
const appData = useLazyLoadQuery<AppQuery>(query, {});

return (
<>
<HomePage currentUser={appData.currentUser}>
<ProfilePage currentUser={appData.currentUser}>
</>
);
}

和以下页面组件:

interface HomePageProps {
currentUser: HomePage_currentUser$key | null;
}
const currentUserFragment = graphql`
fragment HomePage_currentUser on User {
id
profileImageUrl
items {
id
name
}
}
`;

export default function HomePage(props: HomePageProps): JSX.Element {
const currentUser = useFragment(currentUserFragment, props.currentUser);
return (
<>
{/* ... */}
<ProfileIcon user={currentUser} >
{/* ... */}
</>
)
}
interface ProfilePageProps {
currentUser: ProfilePage_currentUser$key | null;
}
const currentUserFragment = graphql`
fragment ProfilePage_currentUser on User {
id
profileImageUrl
lastLoggedInTimestamp
}
`;

export default function ProfilePage(props: ProfilePageProps): JSX.Element {
const currentUser = useFragment(currentUserFragment, props.currentUser);
return (
<>
{/* ... */}
<ProfileIcon user={currentUser} >
{/* ... */}
</>
)
}

和以下ProfileIcon分量

interface ProfileIconProps {
currentUser: ???
}
export default function ProfileIcon(props: ProfileIconProps): JSX.Element {
return (
<div>
<img src={props.currentUser.profileImageUrl} />
</div>
)
}

我的主要问题是关于ProfileIcon组件中currentUser支柱的类型。似乎没有干净的方法来重用ProfilePage_currentUser类型和HomePage_currentUser类型的组件,尽管所请求的数据非常相似,并且为了这个组件显然是兼容的。

有什么推荐的方法来处理这个问题,而不是像这样?

interface ProfileIconProps {
currentUser: Omit<ProfilePage_currentUser, ' $refType'>
}

在Relay中,手动提取数据并将其作为prop传递给组件并不是一个好的做法。相反,你应该在ProfileIcon组件上有一个片段,让Relay负责将相同的数据传递给你的组件。

所以你需要在ProfileIcon组件中创建一个片段,并查询profileImageUrl,然后在HomePage_currentUserProfilePage_currentUser片段中添加这个片段,继电器将为你照顾其余的。

interface ProfileIconProps {
currentUser: ProfileIcon_currentUser$key | null;
}
const currentUserFragment = graphql`
fragment ProfileIcon_currentUser on User {
profileImageUrl
}
`;

export default function ProfileIcon(props: ProfileIconProps): JSX.Element {
const currentUser = useFragment(currentUserFragment, props.currentUser);
return (
<div>
<img src={props.currentUser.profileImageUrl} />
</div>
)
}

添加ProfileIcon_currentUser片段

const currentUserFragment = graphql`
fragment HomePage_currentUser on User {
id
items {
id
name
}
...ProfileIcon_currentUser
}

';

在ProfilePage组件中添加ProfileIcon_currentUser片段

const currentUserFragment = graphql`
fragment ProfilePage_currentUser on User {
id
lastLoggedInTimestamp
...ProfileIcon_currentUser
}
`;

使用此模式的优点之一是,如果您在其他地方(甚至不在相同的react节点树层次结构中)对User有一个突变,例如您更改profileImageUrl,然后ProfileIcon将自动接收新的profileImageUrl,而无需传递profileImageUrl的新值。实际上,Relay存储将使用突变负载上的新值进行更新,并且一旦存储中有新的更新,它将把该数据传递给使用该数据的任何组件。

相关内容

最新更新