web前端培训React 泛型组件

  • Post author:
  • Post category:其他



以下文章来源于方应杭讲编程


案例

假设我们要做一个很简单的 Show 组件,用法如下:

<Show

content=”hi”

onClick={c => console.log(c)}

/>

Show 组件会展示 content,并在用户点击 content 时把 content 传给 onClick。

因此代码中的 c 和 content 总是相等的。

你会如何实现 Show 组件呢?假设你是这么写的:

interface Props{

content: any

onClick?: (arg: any) => void

}

function Show(props: Props){

const {content, onClick} = props

return (

<div>

{content}

<button

onClick={()=> onClick?.(content)}

>

Click me

</button>

</div>

)

}

确实能完成功能,但是用到了两个 any,这不是 TypeScript,这是 AnyScript_

前端培训


改写

于是你可以打算进行改写,你发现 content 和 onClick 的参数其实总是一样的,于是你写成这样:

interface Props<T>{

content: T

onClick?: (arg: T) => void

}

但此时,Show 报错了:

报错内容是 Props 需要接受一个参数 T,于是你让 Show 接受一个参数 T,再把 T 传给 Props:

function Show<T>(props: Props<T>){ …

报错消除了。

于是 Show 组件就可以这样用了:

<Show<string>

content=”hi”

onClick={c => console.log(c)}/>

由于 TypeScript 有自动推断功能,所以可以从 content 自动推断出 T = string,所以可以简写成这样:

<Show

content=”hi”

onClick={c => console.log(c)}/>

这种写法跟最开始的写法一模一样,但是我们得到了一个大好处:c 的类型不再是 any 了,而是跟 content 保持一致:

以上,就是泛型组件的简单演示。

不过值得注意的是,上面的 Show 被我声明为普通函数,并没有被声明为 React.FunctionComponent,因为一旦声明成 React.FunctionComponent,就没法再加泛型了。

另外,如果你喜欢用 Class 组件,那么可以把 Show 组件写成这样:

class Show<T> extends Component<Props<T>> {

render(){

return (

<div>

{this.props.content}

<button

onClick={

()=> this.props.onClick?.(this.props.content)}

>

Click me

</button>

</div>

)

}

}

export default function App() {

return (

<Show content=’hi’ onClick={c => console.log(c)} />

);

}


实际场景

在实际工作中,我们什么时候会遇到泛型组件呢?

web前端培训

这里有一个典型的例子:Table 组件。

假设我们的 Table 组件是这样用的:

<Table

data={[

{id:1, name:’Alice’,age:16,gender:’女’},

{id:2, name:’Bob’,age:16,gender:’男’},

{id:3, name:’Carry’,age:16,gender:’男’},

]}

cols={[

{key:’name’, title:’姓名’},

{key:’age’, title:’年龄’}

]}

/>

三条数据,只展示 name 和 age,我们如何确保 cols 里的 key 一定是 data 里面的字段名呢?

用泛型即可:

interface Props<T>{

data: T[],

cols: {

key: keyof T // cols 的 key 必须是 data item 的字段名

title: string

}[]

}

function Table <T>(props: Props<T>) {

const {data, cols} = props

return (

<table>

{data.map(d =>

<tr>

{cols.map(c =>

<td>{d[c.key]}</td>

)}

</tr>

)}

</table>

)

}

也就是说,当你需要两个 props 的类型有关联的时候,往往可以使用泛型组件来实现。


不解

不过目前我很疑惑下面这段代码翻译成 TypeScript 是怎样的:

<Show<string> />

虽然我知道这段代码翻译成 JavaScript 是

React.createElement(Show)

// 或

_jsx(Show)

但我并不知道翻译成 TypeScript 应该怎么写,尤其是 <string> 会被放在哪。