react项目中使用装饰器decorators和typeScript

这篇文章主要是用来记录在 create-react-app 中使用装饰器 Decorator 和 typeScript,使用装饰器 Decorator 的前提是已经使用 create-react-app 完成了项目的创建。如果你还不知道怎样使用 create-react-app 创建 react 项目,可以点击这里查看详细内容

1. 装饰器 Decorator

装饰器(Decorator)是ES6的新特性,是一种与类(class)相关的语法,用来注释或修改类和类方法。Decorator 提案经过了大幅修改,目前还没有定案,但是在开发项目中,依旧是可以使用的。

使用装饰器,要用 Babel 来进行转换,用到的插件是 @babel/plugin-proposal-decorators

1.1 安装:

在终端中执行下面的命令,安装 @babel/plugin-proposal-decorators
yarn add @babel/plugin-proposal-decorators -D

1.2 修改webpack配置文件

如果你还不知道怎么在 create-react-app 中修改 webpack 配置项,点击这里查看第3章内容 create-react-app 高级配置

在项目中 webpack 配置的文件 config-overrides.js 增加下面的内容:

const {override,addBabelPlugin} = require('customize-cra');
const path = require('path')

module.exports = override(
  addBabelPlugin( [
    //引入装饰器Decorator
    "@babel/plugin-proposal-decorators", { "legacy": true }
  ])
)

1.3 语法

装饰器是一种函数,写成@ + 函数名。它可以放在类方法的定义前面

例如:@fn class Box{}

  • fn 为函数名,也就是装饰器,在该函数中可以修改类的行为,比如给类添加静态属性或者实例属性;
  • Box 是定义的一个类;
  • fn 中的参数是后面的类本身
  • 装饰器对类的行为的改变,是代码编译时发生的,而不是在运行时。这意味着,装饰器能在编译阶段运行代码。也就是说,装饰器本质就是编译时执行的函数;
  • 装饰器只能用于类的方法不能用于函数,因为存在函数提升。

1.4 使用

给 Box 类添加静态属性 title,和实例属性 article:

import React from 'react';
import ReactDOM from 'react-dom';

function Foo(target){
  target.title="Decorator"
  target.prototype.article="decorator是一种语法,用来注释或修改类和类方法"
}

@Foo
class Box extends React.Component{
  render(){
    return(
      <div>
        <h1>{Box.title}</h1>
        <div>{this.article}</div>
      </div>
    )
  }
}

ReactDOM.render(
  <Box />,
  document.getElementById('root')
);

如果在调用装饰器函数的时候,需要往里面传入参数,则在函数中需要 return 一个函数,return 返回的函数的参数为类本身。

import React from 'react';
import ReactDOM from 'react-dom';

function Foo(params,target){
  //params为下面传过来的参数,这里是2020
  //target为要装饰的类本身,这里是Box
  return function(target){
    target.title="Decorator"
    target.prototype.article="decorator是一种语法,用来注释或修改类和类方法"
  }
}

@Foo("2020")
class Box extends React.Component{
  render(){
    return(
      <div>
        <h1>{Box.title}</h1>
        <div>{this.article}</div>
      </div>
    )
  }
}

ReactDOM.render(
  <Box />,
  document.getElementById('root')
);

2. typeScript

typeScript 是 javaScript 的一个超集,它的优点是对 ES6 支持的比较好,可以增加代码的可读性和可维护性。

点击查看 typeScript 简介和基础类型

2.1 React 项目中添加 typeScript

创建新项目:

要使用 TypeScript 启动新的 Create React App 项目,你可以在终端中执行下面的命令,在当前目录下创建基于 ts 的 react 项目:

npx create-react-app ./ --typescript
#或者
yarn create react-app ./ --typescript

创建成功后,会看到在根目录下多了一个 tsconfig.json 配置文件,执行npm start启动服务。
在这里插入图片描述
更多关于 tsconfig.json 的配置项,可以查看官网介绍

如果是添加 TypeScript 到 已有的 Create React App 项目中:

在终端中执行下面的命令安装 TypeScript:

npm install --save typescript @types/node @types/react @types/react-dom @types/jest
# 或者
yarn add typescript @types/node @types/react @types/react-dom @types/jest

安装完成后,将任何文件重命名为 TypeScript 文件(例如 src/index.js 重命名为 src/index.tsx )并重新启动服务器。

2.2 ts函数组件

import React from 'react'

interface IProps {	//interface定义数据类型
  name:string;	//确定属性,必须要传
  age?:number	//?表示该属性为可选择属性,可以不传
}

function Hello(props:IProps){
  return (
  	<h1>name:{props.name}-age:{props.age}</h1>
  )
}

export default Hello;

2.3 ts类组件

import React, { Component } from 'react'
import ReactDOM from 'react-dom'

interface IProps {  
  count:number;	//确定属性  
  age?:string;	//?表示该属性为可选择属性,可以不传
  [propName:string]:any	//任意属性,确定属性和可选属性必须是任意属性的子集
}

interface IState {
  count:number,
  username?:string
}

class Counter extends Component<IProps,IState> {
  constructor(props:IProps) {
    super(props);
    this.state ={
      count:props.count
    }
  }

  updateCount(count:number){
    this.setState({
      count
    })
  }

  onIncrement=()=>this.updateCount(this.state.count+1);
  onDcrement=()=>this.updateCount(this.state.count-1);

  render() {
    return (
      <div>
        <button onClick={this.onDcrement}>-</button>
        { this.state.count }
        <button onClick={this.onIncrement}>+</button>
      </div>
    )
  }
}

ReactDOM.render(
  <Counter count={2}/>,
  document.getElementById('root')
);

2.4 ts高阶组件

组件的类型是 React.ComponentType

import React, { Component,ComponentType } from 'react'
import ReactDOM from 'react-dom'

class App extends Component {
  render() {
    return (
      <div> react.js 是一个构件用户界面的库 </div>
    )
  }
}

const withCopyrigth = (Comp:ComponentType) => {
  return class NewComp extends Component {
    render() {
      return (
        <>
          <Comp></Comp>
          <div>版权所有:2020-0430</div>
        </>
      )
    }
  }
}

const Apps = withCopyrigth(App);

ReactDOM.render(
  <Apps />,
  document.getElementById('root')
);

2.5 ts事件处理

import React, { MouseEvent } from 'react'

type Props = {
  children: React.ReactNode,
  buttonClick(e: MouseEvent): void,
  touchMove(e: React.TouchEvent): void
}

const Button = ({ children, buttonClick, touchMove }: Props) => {
  return (
    <>
      <button onClick={buttonClick}>{children}</button>
      <button onTouchMove={touchMove}>{children}</button>
    </>
  )
}

class App extends React.Component {

  handleClick = (event: MouseEvent) => {
    console.log(event.clientX)
  }

  handleTouch = (event: React.TouchEvent) => {
    console.log(event.touches)
  }

  render() {
    return (
      <Button touchMove={this.handleTouch} buttonClick={this.handleClick}>确定</Button>
    )
  }
}

export default App;

2.6 ts Promise

interface IResponse<T> {
  message: string,
  code: number,
  result: T
}

type Params = {
  url: string,
  type: 'post' | 'get',
  data?: any
}

function MyRequest(data: Params): Promise<IResponse<number[]>> {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({
        code: 1,
        message: "获取数据成功",
        result:[1,2,3]
      })
    }, 1000)
  })
}

猜你喜欢

转载自blog.csdn.net/Charissa2017/article/details/105853351