reactjs - 使用 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>
)
}
我的主要问题是关于组件中currentUser
道具的类型。尽管请求的数据非常相似并且显然为了这个组件而兼容,但ProfileIcon
似乎没有干净的方法可以将组件重新用于ProfilePage_currentUser
类型和类型。HomePage_currentUser
除了这样的事情之外,还有什么推荐的方法来处理这个问题吗?
interface ProfileIconProps {
currentUser: Omit<ProfilePage_currentUser, ' $refType'>
}
解决方案
在 Relay 中,手动提取数据并将其作为道具传递给组件并不是一个好习惯。相反,您应该在ProfileIcon
组件上有一个片段,并让 Relay 负责将相同的数据向下传递给您的组件。
因此,您需要在 ProfileIcon 组件中创建一个片段并查询,profileImageUrl
然后在两者中添加此片段,HomePage_currentUser
片段ProfilePage_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>
)
}
在 HomePage 组件中添加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
}
`;
使用此模式的一个优点是,如果您在其他地方对 User 进行了突变(即使不在同一个反应节点树层次结构中)并且假设您更改了,profileImageUrl
那么 ProfileIcon 将profileImageUrl
自动接收新的,而无需您传递新的profileImageUrl 的值。实际上,中继存储将使用突变有效负载上的新值进行更新,并且一旦存储中有新的更新,它就会将该数据传递给使用该数据的任何组件。
推荐阅读
- python - 在 matplotlib 图中裁剪一系列值
- javascript - 错误错误:未捕获(承诺):TypeError:无法在离子4 Angular中设置未定义的属性“设备”
- python - 为什么我在尝试以管理员身份写入文件时在 Python 中收到权限错误?
- reactjs - 单击导航链接后重定向到以前的状态?
- ios - 不同的视图控制器segue
- sql - SQL 按重复行降序排列
- php - 依赖N级下拉列表
- python - 如何在一个输入中包含多个字符串以在一行中打印?
- php - 如何使用 php 在 ftp 服务器上创建受密码保护的 zip 文件
- javascript - 排序对象列表javascript