在react-ts项目中实现一个自定义装饰器

安装依赖

npm i @babel/plugin-proposal-decorators -D

配置.babelrc

{
  "plugins": [
    [
      "@babel/plugin-proposal-decorators",
      {
        "legacy": true
      }
    ]
  ]
}

实现一个简单的日志打印方法

// TestDecorator.tsx
function Log(target: any, name: string, descriptor: any): any {
  // 这里是缓存原始值,用于在拦截器最后运行原始方法
  const oldValue = descriptor.value;

  // 实现一个拦截器,在拦截器中实现日志打印,并在最后返回旧值的结果
  descriptor.value = function log() {
    // 实现日志打印
    console.log(
      `%c[${logid}]调用了方法:${name},参数为:`,
      "color: orange;",
      Array.from(arguments)
    );
   	// 调用原始方法实现原始逻辑
    return oldValue.apply(this, arguments);
  };
	// 最后返回一个新的描述器
  return descriptor;
};

export default Log;

调用装饰器

// TestComponent.tsx
import * as React from "react";
import Log from "./TestDecorator";

// 属性接口
export interface IProps {
  name: string;
  age?: number;
}

class TestComponent extends React.Component<IProps, object> {
  // 状态
  public state: any = {
    sum: 0
  };
	// 调用装饰器
  @Log
  public add(a: number, b: number): void {
    this.setState({
      sum: a + b
    });
  }

  public render() {
    const { name, age = 0 } = this.props;
    const { sum } = this.state;
    return (
      <div
        onClick={() => {
          this.add(sum, age);
        }}
      >
        你好,我叫:{name},计数器:{sum},{age ? `今年${age}岁了` : ""}
        {this.props.children}
      </div>
    );
  }
}

export default TestComponent;

实现一个可传递参数的装饰器

// TestDecorator.tsx
// 定义一个修饰器
function Logger(logid: string, handler: (name: string) => void) {
  // 采用高阶函数的方式进行封装,可接受额外的参数,如外层可接受logid和触发的回调,返回的方法才是真正对类或者方法处理的方法
  return function Log(target: any, name: string, descriptor: any): any {
    // 这里是缓存旧的方法,也就是上面那个add()原始方法
    const oldValue = descriptor.value;

    // 这里修改了方法,使其作用变成一个打印函数
    // 最后依旧返回旧的方法,真是巧妙
    descriptor.value = function log() {
      console.log(
        `%c[${logid}]调用了方法:${name},参数为:`,
        "color: orange;",
        Array.from(arguments)
      );
      // 触发回调原函数
      const args = Array.prototype.slice.call(arguments);
      args.unshift(name);
      handler.apply(this, args);
      return oldValue.apply(this, arguments);
    };

    return descriptor;
  };
}

export default Logger;


// TestComponent.tsx
import * as React from "react";
import Log from "./TestDecorator";

export interface IProps {
  name: string;
  age?: number;
}

class TestComponent extends React.Component<IProps, object> {
  public state: any = {
    sum: 0
  };
  
  @Log("日志打印", (name, ...args) => {
    console.log(`触发回调[${name}]:`, args);
  })
  public add(a: number, b: number): void {
    this.setState({
      sum: a + b
    });
  }

  public render() {
    const { name, age = 0 } = this.props;
    const { sum } = this.state;
    return (
      <div
        onClick={() => {
          this.add(sum, age);
        }}
      >
        你好,我叫:{name},计数器:{sum},{age ? `今年${age}岁了` : ""}
        {this.props.children}
      </div>
    );
  }
}

export default TestComponent;


这样,我们就已经实现了一个简单的日志打印的装饰器了。从上面的实例我们可以看出,其实装饰器本质上就是React中的HOC,即高阶组件,这个高阶函数接收一个方法、类、变量等参数,在内部进行一定的出处理后返回一个新的方法、类、变量,以此来达到我们的要对目标方法、类、变量进行预处理的目的。

发布了32 篇原创文章 · 获赞 16 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/u010651383/article/details/104675942