TS入门012ts和React之Class组件

生成 ts-react 项目

1
2
3
4
5
6
7
8
9
mkdir ts-react-demo

cd ts-react-demo

# 创建项目
yarn create react-app . --typescript

# 初始化成功,启动项目
yarn start
  • 移除无用文件
  • 修改 src/index.tsx

    1
    2
    3
    4
    5
    import React from 'react';
    import ReactDOM from 'react-dom';
    import App from './App';

    ReactDOM.render(<App />, document.getElementById('root'));
  • 修改 src/App.tsx

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import React from 'react';
    import Button from './components/button'

    class App extends React.Component{
    render(){
    return (
    <div className="App">
    <Button>你好</Button>
    </div>
    )
    }
    }

    export default App;
  • 修改 src/components/button.tsx

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import React from 'react';
    import './button.css';

    class Button extends React.Component{
    render(){
    return (
    <div className="button">{this.props.children}</div>
    )
    }
    }

    export default Button;
  • 修改 src/components/button.css

    1
    2
    3
    4
    5
    6
    7
    8
    9
    .button{
    border:1px solid grey;
    display: inline-block;
    justify-content: center;
    align-items: center;
    padding: 2px;
    border-radius: 4px;
    box-shadow: 0 0 3px black;
    }
  • 此时初步代码完成了

如何控制 Button 的大小? 传递 size

  • 直接传递报错!
    1
    2
    3
    4
    5
    6
    7
    妄图直接传递 size 属性

    <Button size="big">你好</Button>


    不能将类型“{ children: string; size: string; }”分配给类型“IntrinsicAttributes & IntrinsicClassAttributes<Button> & Readonly<{}> & Readonly<{ children?: ReactNode; }>”。
    类型“IntrinsicAttributes & IntrinsicClassAttributes<Button> & Readonly<{}> & Readonly<{ children?: ReactNode; }>”上不存在属性“size”。ts(2322)

泛型的使用

  • 给 Button 通过泛型传递参数列表< size: string >
  • 此时不报错了!!!
  • 如果你想要给 Button 传递参数 就要把属性写到 泛型<>
1
2
3
4
5
6
7
class Button extends React.Component<{ size: string }>{
render(){
return (
<div className="button">{this.props.children}</div>
)
}
}

假如我有10个属性怎么办?

泛型里的内容太多了

1
2
3
4
5
6
class Button extends React.Component<
{ size: string ,
xxx1: string ,
xxx2: string ,
...
}>{...}

你可以这样

1
2
3
4
5
6
7
8
9
10
11
12
13
type Props = {
size: string,
xxx:string,
xxx2:string,
onClick:()=>void
}
class Button extends React.Component<Props>{
render(){
return (
<div className="button">{this.props.children}</div>
)
}
}

你还可以使用接口 interface

1
2
3
4
5
6
7
8
9
10
11
12
13
interface IProps {
size: string,
xxx:string,
xxx2:string,
onClick:()=>void
}
class Button extends React.Component<IProps>{
render(){
return (
<div className="button">{this.props.children}</div>
)
}
}

如果我有 state 怎么办?

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
// ? 代表 可选参数 反之必填
interface IProps {
size: string,
xxx?:string,
xxx2?:string,
onClick?:()=>void
}
interface IState {
n : number
}

class Button extends React.Component<IProps,IState>{
// 这里 必须给 props 指定类型 否则报错
constructor(props:IProps){
super(props)
this.state = {
n:1
}
}
render(){
return (
<div className="button">
{this.props.children}

</div>
)
}
}

displayName 是什么

  • 给你组件起的名字,如果你的google 里安装了 react devtools 你的组件就会显示你设置的名字
1
2
3
4
5
6
7
class Button extends React.Component{
// 开发者工具里显示的名字
static displayName = "HjxButton"
render(){
...
}
}

默认 props 值

1
2
3
4
5
6
7
8
9
10
11
interface IProps {
size: string,
}

class Button extends React.Component<IProps>{
// 这里给 size 设置默认值 当你不传递的时候
static defaultProps = {
size : 'normal'
}
...
}

TS 帮你做分析

  • 断言
  • if 判断
  • 规避 js undefined + 1 = NaN 的bug
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
34
35
36
37
interface IProps {
size: string,
xxx?:string,
xxx2?:string,
onClick?:()=>void
}
interface IState {
n : number
}

class Button extends React.Component<IProps>{
// 这里给 size 设置默认值 当你不传递的时候
static defaultProps = {
size : 'normal',
xxx: 'aaa'
}
constructor(props:IProps){
super(props)
// 这句话报错 因为 xxx 可能是 undefined
// undefined 不能直接和数字 + 操作
// console.log(this.props.xxx + 1)
// 解决办法就是 加一个 “!”
// 就是断言 保证它不会为空 ,出问题自己负责
console.log(this.props.xxx! + 1)
// 或者这样
console.log(this.props.xxx as string + 1)
// 或者还可以这样
if(this.props.xxx === undefined){

}else{
console.log(this.props.xxx + 1)
}
}
render(){
...
}
}

onClick 事件如何写

src/App.tsx

1
2
3
4
5
6
7
8
9
10
11
12
13
class App extends React.Component{
// 参数也要声明类型
onClick(e:React.MouseEvent){
console.log(e)
}
render(){
return (
<div className="App">
<Button onClick={this.onClick}>你好</Button>
</div>
)
}
}

src/components/button.tsx

1
2
3
4
5
6
7
8
9
10
11
12
13
interface IProps {
// 声明它的类型
onClick?: React.MouseEventHandler
}
class Button extends React.Component<IProps>{
render(){
return (
<div className="button" onClick={this.props.onClick}>
{this.props.children}
</div>
)
}
}

我想打印 click 事件源的一些东西

src/App.tsx 里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 /*
onClick(e:React.MouseEvent){
console.log(e)
// style 竟然标红了
// 提示 类型“EventTarget”上不存在属性“style”。
//console.log(e.target.style.width)
// 你只能断言
// const div = e.target as HTMLDivElement;
// console.log(div.style.width)

// 断言还是有风险,因为 如果 Button 里传递的是 <span>hi</span>你好
// 断言就有问题了 它不是 div 有可能是 span
}
*/
// 泛型参数 指定触发事件的元素一定是个 div
onClick(e:React.MouseEvent<HTMLDivElement>){
console.log(e.currentTarget)
const div = e.currentTarget;
console.log(div.style.width)
}

state 的一些问题

  • 新建 src/components/button2.tsx
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 from 'react';
import './button.css';

interface IProps {
size?: string,
}
interface IState {
n : number
}

class Button2 extends React.Component<IProps,IState>{
constructor(props:IProps){
super(props)
this.state = {
n:1
}
}
onClick(){
this.x();
}
x(){
console.log('x');
}
render(){
return (
<div className="button" onClick={this.onClick}>
{this.props.children}
</div>
)
}
}

export default Button2;

点击后直接报错 因为 this 是 undefined

解决办法:onClick写成箭头函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Button2 extends React.Component<IProps,IState>{
...
onClick = () => {
this.x();
}
x(){
console.log('x');
}
render(){
return (
<div className="button" onClick={this.onClick}>
{this.props.children}
</div>
)
}
}

还有一种不推荐的方式: bind(this)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Button2 extends React.Component<IProps,IState>{
...
onClick(){
this.x();
}
x(){
console.log('x');
}
render(){
return (
<div className="button" onClick={this.onClick.bind(this)}>
{this.props.children}
</div>
)
}
}

补充:事件有那些种类

  • React.MouseEventHandler
  • React.KeyboardEventHandler
  • React.TouchEventHandler
  • React.WheelEventHandler

如果你的 props 是 加”?”

  • 使用时候加断言

onClick 的 this问题

  • 箭头函数onClick = () => { ... }
  • bind(this)

参考代码 ts012