Сделайте компонент повторно используемым с помощью Typescript в React

Создавая приложение React, я хочу сделать свой код как можно более СУХИМ. Я впервые начал использовать Typescript в этом проекте и столкнулся с проблемой повторного использования моих компонентов, где JSX может быть одинаковым для разных случаев, но меняются типы и интерфейсы.

Вот реальный пример: приведенный ниже код представляет собой компонент React, созданный с помощью TypeScript, Apollo/GraphQL и Redux. Он возвращает таблицу всех футбольных команд в моей БД, полученную из внутреннего API.

Дело в том, что я хотел бы использовать этот же компонент для отображения таблицы игр, таблицы игроков и т.д.

А я застрял, например, со своим Team интерфейсом. У каждой команды есть только id и name; но у каждой игры есть date, homeTeam и awayTeam, aсчет` и т. д.

Следовательно, как я могу управлять своими интерфейсами и своими типами, чтобы я мог повторно использовать этот компонент?

import React from 'react';
import { connect } from 'react-redux';
import { setView, toggleDeleteElemModal } from '../../redux/actions';

import gql from 'graphql-tag';
import { Query } from 'react-apollo';
import { ApolloError } from 'apollo-client';

import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faInfo, faEdit, faTrash } from '@fortawesome/free-solid-svg-icons';

interface SectionTableProps {
  setView: typeof setView
  toggleDeleteElemModal : typeof toggleDeleteElemModal
}

interface Team {
  id: string;
  name: string;
}

interface Data {
  allTeams?: Team[];
}

interface SectionTableQueryProps {
    allTeams: Team[];
    error?: ApolloError;
    loading: boolean;
}

const GET_ALL_TEAMS = gql`
  query {
    allTeams {
      id
      name
    }
  }
`;

class SectionTableQuery extends Query<Data, {}> {}

const SectionTable = (props: SectionTableProps) => (
  <table className = "table table-hover table-responsive">
    <thead>
      <tr>
        <th scope = "col">ID</th>
        <th scope = "col">Name</th>
        <th scope = "col">Actions</th>
      </tr>
    </thead>
      <SectionTableQuery query = {GET_ALL_TEAMS}>
      {({ data: { allTeams = [] } = {}, error, loading }) => {
        if (loading) {
          return <tbody><tr><td>LOADING</td></tr></tbody>
        };
        if (error !== undefined) {
          return <tbody><tr><td>ERROR</td></tr></tbody>
        };
        return (
          <tbody>
            {allTeams.map((team: Team) => (
                <tr key = {team.id}>
                  <th scope = "row">{team.id}</th>
                  <td>{team.name}</td>
                  <td className = "d-flex justify-content-between">
                  <div onClick = {() => props.setView("info")}>
                    <FontAwesomeIcon icon = {faInfo} />
                  </div>
                  <div onClick = {() => props.setView("edit")}>
                    <FontAwesomeIcon icon = {faEdit} />
                  </div>
                  <div onClick = {() => props.toggleDeleteElemModal()}>
                    <FontAwesomeIcon icon = {faTrash} />
                  </div>
                  </td>
                </tr>

            ))}
          </tbody>
        );
      }}
    </SectionTableQuery>
  </table>
)

const mapDispatchToProps = { setView, toggleDeleteElemModal }

export default connect(null, mapDispatchToProps)(SectionTable);
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
0
902
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете использовать общие типы для компонентов JSX для этого поведения.

class SectionTableQuery extends Query<P, {}> {} // where P is the generic prop

Объявление SectionTable должно было бы принимать этот общий интерфейс P от своего родителя и при рендеринге SectionTableQuery:

const SectionTable<P> = (props: SectionTableProps) => (
  <SectionTableQuery<P> query = {props.query}>  // Assuming you want the query to change, that would be passed as a prop too
  ...
  </SectionTableQuery>
);

Во время рендеринга SectionTable родитель может передать реквизиты, которые он / она хочет.

<SectionTable<ITeam> ... />
<SectionTable<IPlayer> ... />

Это общее приближение того, что вам нужно сделать, похоже, что может быть более одного универсального типа, который вы хотите передать в зависимости от запроса (IData для того, что возвращается из запроса и IItem для самого элемента`)

PS: общие компоненты доступны по адресу Машинопись 2.9.

Спасибо за помощь ! Действительно, Generics — это волшебство, которое я искал.

Uj Corb 19.04.2019 14:48

Другие вопросы по теме