Как лучше всего повторно использовать компоненты во фрагментах с помощью React/Relay/Typescript?

Я делаю веб-приложение с React, Relay (экспериментальным) и Typescript, и у меня возникают проблемы с повторным использованием компонентов с похожими данными/реквизитами в разных фрагментах.

Допустим, у меня есть следующий запрос Relay и основной компонент приложения:

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'>
}

person BadgerPriest    schedule 21.01.2021    source источник


Ответы (1)


В 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
  }
`;

Одним из преимуществ использования этого шаблона является то, что если у вас есть мутация для пользователя где-то еще (даже не в той же иерархии дерева узлов реакции) и, скажем, вы меняете profileImageUrl, тогда ProfileIcon автоматически получит новый profileImageUrl без вашего обхода. новое значение profileImageUrl. Фактически, хранилище Relay будет обновлено новым значением полезной нагрузки мутации, и как только в хранилище появится новое обновление, оно передаст эти данные всем компонентам, которые используют эти данные.

person Matin Kajabadi    schedule 22.01.2021