构建一个React应用程序,我想让我的代码尽可能的干燥。我在该项目中第一次开始使用Typescript,但是我遇到了组件可重用性的问题,其中JSX在不同情况下可以相同,但是类型和接口会发生变化。
这是一个真实的例子:下面的代码是一个使用TypeScript,Apollo / GraphQL和Redux构建的React组件。它返回从后端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);
答案 0 :(得分: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
是查询返回的内容,{ {1}}(商品本身))
PS:通用组件可从Typescript 2.9
获得