天天看點

TypeScript && React

環境搭建

我們當然可以先用腳手架搭建React項目,然後手動配置成支援TypeScript的環境,雖然比較麻煩,但可以讓你更清楚整個過程。這裡比較麻煩,就不示範了,直接用指令配置好。

1

npx create-react-app appname --typescript

可以安裝一些自己需要的庫及其聲明檔案,例如react-router-dom、axios、ant Design等。如果要安裝ant design,還需要在開發環境庫中安裝一些依賴庫,以幫助實作按需加載。

使用

有類型限制的函數元件

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

import

React from 

"react"

;

import

{ Button } from 

"antd"

;

interface

Greeting {

name: string;

firstName?: string;

lastName?: string;

}

// 沒有使用React.FC

const HelloOld = (props: Greeting) => <Button>你好{props.name}</Button>;

// 使用React.FC泛型類型

const Hello: React.FC<Greeting> = (props) => {

return

(

<Button>Hello {props.name}</Button>

)

};

export

{ Hello, HelloOld };

定義函數元件時,使用React.FC與不使用沒有太多差別,沒有為我們帶來明顯的好處,建議使用正常定義方式。

有類型限制的類元件

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

import

React,{Fragment} from 

"react"

;

import

{ Button } from 

"antd"

;

interface

Greeting {

name: string;

firstName?: string;

lastName?: string;

}

interface

State {

count: number

}

// 泛型類型,第一個傳入參數限制屬性props,第二個限制狀态state(内部資料)

class

HelloClass 

extends

React.Component<Greeting, State> {

state: State = {

count: 0

};

static

defaultProps = {  

// 屬性預設值

firstName: 

""

,

lastName: 

""

,

};

render() {

return

(

<Fragment>

<p>點選了{

this

.state.count}次</p>

<Button onClick={()=>{

this

.setState({count: 

this

.state.count+1})}}>Hello{

this

.props.name}Class</Button>

</Fragment>

);

}

}

export

default

HelloClass;

有類型限制的高階元件

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

import

React from 

"react"

;

import

HelloClass from 

"./HelloClass"

;

interface

Loading {

loading: boolean;

}

function

HelloHoc<P>(params?: any) {

return

function

<P>(WrappedComponent: React.ComponentType<P>) { 

// P表示被包裝元件的屬性的類型

return

class

NewComponent 

extends

React.Component<P & Loading>{ 

// 這裡使用交叉類型,為新元件增加一些屬性,接口Loading定義了新增的屬性聲明

render(){

return

this

.props.loading ? <div>Loading</div> : <WrappedComponent {...

this

.props as P}/>

}

}

}

}

export

default

HelloHoc()(HelloClass);

高階元件在ts中使用會有比較多的類型問題,解決這些問題通常不會很順利,而且會存在一些已知的bug,這不是高階元件本身的問題,而是React聲明檔案還沒有很好地相容高階元件的類型檢查,更好的方式是使用Hooks

有類型限制的Hooks

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

import

React, { useState, useEffect } from 

"react"

;

import

{ Button } from 

"antd"

;

interface

Greeting {

name: string;

firstName?: string;

lastName?: string;

}

const HelloHooks = (props: Greeting) => {

const [ count, setCount ] = useState(0); 

// 設了初值,是以不用定義類型

const [ text, setText ] = useState<string | 

null

>(

null

);

useEffect(()=>{

count > 5 && setText(

"休息一下"

);

},[count]); 

// 第二個參數的作用是,隻有當count改變的時候,函數内的邏輯才會執行。

return

(

<>

<p>你點選了Hooks {count} 次 {text}</p>

<Button onClick={()=>{setCount(count+1)}}>{props.name}</Button>

</>

);

};

export

default

HelloHooks;

事件綁定

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

class

HelloClass 

extends

React.Component<Greeting, State> {

state: State = {

count: 0

};

clickHandle = (e: React.MouseEvent) => { 

// 事件對象e的類型使用内置的合成事件。在回調函數中,e的屬性都會無效

e.persist(); 

// 将該事件從池中删除合成事件,可以正常使用

console.log(e);

// this.setState({count: this.state.count+1})

};

inputHandle = (e: React.FormEvent<HTMLInputElement>) => {

// e.persist();

console.log(e.currentTarget.value); 

// 此時編譯器報錯,認為沒有value屬性,需要指定<HTMLInputElement>泛型類型

// console.log(e.target.value); // 仍然不行

};

render() {

return

(

<Fragment>

<p>點選了{

this

.state.count}次</p>

<Button onClick={

this

.clickHandle}>Hello{

this

.props.name}Class</Button>

<input onChange={

this

.inputHandle}/>

</Fragment>

);

}

}

繼續閱讀