React 泛型组件是什么?

案例

假设我们要做一个很简单的 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)} />
  );
}

实际场景

在实际工作中,我们什么时候会遇到泛型组件呢?这里有一个典型的例子: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 里面的字段名呢?

用泛型即可:

  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> 会被放在哪。

如果你知道,请不吝赐教。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容