React+TypeScript教程之2 - props


由微软推出的TypeScript自从一推出就广受关注,现在无论开发前端React/Vue,还是后端API,很多项目中都广泛接受了TypeScript。下面介绍TypeScript在React props中的使用。

TypeScript

props中简单属性的声明

简单类型

type HelloProps = {
    name: string,
    age: number,
    registered: boolean
}

export default function Hello(props: HelloProps) {
  return <div>
            Hello, {props.name}. 
            You are {props.age} years old. 
            {props.registered? 'You have registered.': 'You havenot registered yet.'}
        </div>;
}

可选属性

这时可以使用 ‘?’ 来声明某个可选属性:

type HelloProps = {
    name: string,
    age?: number,
    registered: boolean
}

在后面使用的时候,可以通过这种方式进行:

  • 首先赋值0到变量中,
  • 如果传递过来属性,则更新变量值
const {age = 0} = props

props中对象属性的声明

当然,也可以声明传递过来的是一个student对象:

type HelloProps = {
    student: {
        name: string,
        age: number,
        registered: boolean
    }
}

export default function Hello(props: HelloProps) {
  return <div>
            Hello, {props.student.name}. 
            You are {props.student.age} years old. 
            {props.student.registered? 'You have registered.': 'You havenot registered yet.'}
        </div>;
}

当传递给Hello组件的时候可以这样:

const stu1 = {name:'Luosi', age: 25, registered: false};

return (
  <div className="App">
    <Hello student={ stu1 }/>
  </div>
);

props中数组类型属性的使用

首先在组件中的声明:

type HelloProps = {
    students: {
        name: string,
        age: number,
        registered: boolean
    }[]
}

export default function Hello(props: HelloProps) {
  return <div>
            {
                props.students.map(student => {
                    return (
                        <li>
                            Hello, {student.name}. 
                            You are {student.age} years old. 
                            {student.registered? 'You have registered.': 'You havenot registered yet.'}
                        </li>
                    )
                })
            }
        </div>;
}

调用时:

function App() {
  const students = [
    {name:'Luosi', age: 25, registered: false},
    {name:'Lucas', age: 18, registered: true},
    {name:'Emily', age: 19, registered: true},
  ];

  return (
    <div className="App">
      <Hello students={ students }/>
    </div>
  );
}

在props中使用联合类型union

在有些场合,需要对传递过来的参数值进行限定,这个时候可以使用union type:

type HelloProps = {
    programme: 'UG' | 'PG';
}

export default function Hello(props: HelloProps) {
  return <div>
            <h2>{props.programme}</h2>
        </div>;
}

这样在调用时只能传递UG或者PG,其余值都会报错:

<Hello programme='UG'/>

定义子元素类型

传递字符串到子元素

有些时候在调用一个React组件的时候,并非想要通过属性传递参数,而是在标签内传递,比如这样:

<Header>
  Some text
</Header>  

那么在Header组件中就需要这样声明:

type HeaderProps = {
  children: string
}

export const Header = (props: HeaderProps) {
  return <h2>{props.children}
}

传递React标签到子元素

首先,定义对应的props类型:

type HelloProps = {
    children: React.ReactNode
}

export default function Hello(props: HelloProps) {
  return <div>
            {props.children}
        </div>;
}

这里注意,自从React 17.x开始,可以不用引入React就直接使用。

其次,在调用时传递子元素:

<Hello>
  <h2>This is a tilte</h2>
  <p>This is a paragraph</p>
</Hello>

声明事件处理函数类型

不含参数和返回值的事件处理函数

type HelloProps = {
    handleClick: () => void
}

export default function Hello(props: HelloProps) {
  return <div>
            <button onClick={props.handleClick}>Click me!</button>
        </div>;
}

在调用时:

function App() {
  
  const handleClick = () => {
    alert('Clicked!');
  }
  return (
    <div className="App">
      <Hello handleClick={ handleClick }/>
    </div>
  );
}

指定具体事件类型

这时需要使用泛型来指定具体事件来源的类型

type HelloProps = {
    handleClick: (event: React.MouseEvent<HTMLButtonElement>) => void
}

export default function Hello(props: HelloProps) {
  return <div>
            <button onClick={(event) => props.handleClick(event)}>Click me!</button>
        </div>;
}

调用部分:

const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
  console.log('Clicked!', event);
}

同时传递其他参数

组件声明部分:

import React from "react";

type HelloProps = {
    handleClick: (event: React.MouseEvent<HTMLButtonElement>, name: string) => void
}

export default function Hello(props: HelloProps) {
  return <div>
            <button onClick={(event) => props.handleClick(event, 'luosi')}>Click me!</button>
        </div>;
}

调用组件:

function App() {
  const handleClick = (event: React.MouseEvent<HTMLButtonElement>, name: string) => {
    console.log('Clicked!', event, name);
  }
  return (
    <div className="App">
      <Hello handleClick={ handleClick }/>
    </div>
  );
}

输入组件的声明

组件部分:

import React from "react";

type HelloProps = {
    defaultValue: string
    handleChange: (event: React.ChangeEvent<HTMLInputElement>) => void
}

export default function Hello(props: HelloProps) {
  return <div>
            <input type='text' placeholder={props.defaultValue} onChange={props.handleChange} />
        </div>;
}

调用部分:

function App() {
  
  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    console.log(event.target.value);
  }
  return (
    <div className="App">
      <Hello defaultValue="init value" handleChange={ event => handleChange(event) }/>
    </div>
  );
}

传递styles

由于React已经将所有CSS属性封装好(React.CSSProperties),因此这时就可以充分利用TS的类型检测功能来提示我们非法的style属性声明。

组件定义:

type HelloProps = {
    styles: React.CSSProperties
}

export default function Hello(props: HelloProps) {
  return <div style={props.styles}>
            Hello TypeScript
        </div>;
}

调用部分:

<Hello styles={{border: '1px solid blue', backgroundColor: 'yellow'}}/>

在props的类型声明中中使用另一个组件类型

假设我们有Student组件:

type StudentProps = {
  name: string
  age: number
  address: string
}

export default function Student(props: StudentProps) {
  return (<div>
    <p>Name: {props.name}</p>
    <p>Age: {props.age}</p>
    <p>Address: {props.address}</p>
  </div>);
}

接下来想要做一个StudentFilter组件,对所有传递进来的Student进行筛选:

import React from 'react';
import Student from './Student';

export default function StudentFilter(props: React.ComponentProps<typeof Student>) {
  return <div>
    {props.age > 20? (
      <Student {...props}/>
    )
    :
    (<></>)
    }
  </div>;
}

可以看到,上面的类型声明中,就使用到了Student组件的类型:**props: React.ComponentProps**。

在声明之后,就可以直接使用类似:props.age 来访问其属性值了。

调用部分:

<div className="App">
  <StudentFilter name="Paul" age={22} address="123 Fake Street"/>
  <StudentFilter name="Lucy" age={18} address="124 Fake Street"/>
</div>

文章作者: 逻思
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 逻思 !
  目录