Remix 中没有中间件,面对重复的代码应该如何是好?

一、问题

Remix 目前还没有中间件,开发路由时,有些公用的代码需要重复的编写。例如每一个路由 action/loader 都需要判断是否授权。

重复是我们不愿意看到的。

那么有没有办法解决重复的问题?

二、别的框架是如何解决重复问题的?

  • express: 中间件

大部分框架都是使用中间件来解决重复的代码问题。但是明显现在 Remix 还没有中间件支持。

  • 装饰器函数

一个装饰器在写好了,可以在类中各种装饰。但是装饰器也是有限制了的。只能在 class 中使用。

到此我们就引出了我们的正题:

在 Remix 中使用 class static method + 装饰器,解决重复代码大量重复的问题。

三、问题代码

ts 复制代码
export const action: ActionFunction = async ({
  request,
  params,
}: ActionFunctionArgs) => {
  const session = await getSession(request.headers.get("Cookie"));
  const lang = params?.lang || defaultLang;

  const dataDto = await request.json();
  let validateDataDto: TLogin;
   // 登录流程...
};

这是一个简单的 action 处理,如果我们登录,每次进入需要授权的页面都需要先进行授权和认证,显示的调用与正常业务无关的内容。

四、为什么会思考到静态函数?

ts 复制代码
const date = Date.now()

Date 是 JS 内置的一个函数,now 方法就是一个静态方式,说明其实我们隐式写 JS、TS 的时候一直在与静态方法打交道。然后再 TS 装饰器中不能直接修饰函数,而可以修饰静态方式。这样我们就可以使用装饰器,在对静态函数进行修饰了。

五、ts 中的 class + 静态函数

ts 复制代码
function console() {
    console.log("loader call")
}
export class LoginHandler {
    @console
    static loader() {}
     @console
    static action() {}
}

console 的函数用于装饰 loader 在 loader 函数调用之前调用。在我们 Remix 路由中,我们就可以直接导入class类型和静态方法。

ts 复制代码
import {LoginHandler} from '~/LoginHandler'

export const action: ActionFunction = LoginHandler.action
export const loader: ActionFunction = LoginHandler.loader

当然如果有更加项目可能逻辑比这个复杂,下面我们系统的 TS 的装饰器内容。

六、装饰器学习资源

七、在 TS stage 2 下中使用装饰器需要完成以下步骤

注意:虽然装饰器已经到了第三个阶段,但是以下还是

ts.config 配置: 基础配置

ts 复制代码
{
  "compilerOptions": {
    "target": "ES5",
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
  }
}

如果要支持反射

sh 复制代码
npm i reflect-metadata --save
ts 复制代码
{
  "compilerOptions": {
    "target": "ES5",
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
  }
}

八、装饰器分类

  • 类装饰器:应用于类构造函数,可以用来修改类的行为或元数据。
  • 方法装饰器:应用于类的方法,可以修改方法的行为或元数据。
  • 访问符装饰器: 应用于类的放问题,可以修改该访问器的行为和元数据。
  • 属性装饰器:应用于类的属性,可以修改属性的行为或元数据。
  • 参数装饰器:应用于类的构造函数或方法的参数,可以修改参数的行为或元数据。

九、普通装饰器和装饰器工厂

就是一个带有 target 参数的函数:

ts 复制代码
function console(target) {
    // do some things
}

target 就是我们装饰的目标(类,函数,属性,函数参数)

装饰器工厂,其实就是一个典型的 JavaScript 闭包函数:

ts 复制代码
function color(value: string) {
  return function (target) {
    // do something with 'target' and 'value'...
  };
}

很简单:函数和闭包函数,以及它们的参数需要熟悉。

十、方法装饰器

ts 复制代码
function MethodDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log("Method Decorator called on: ", propertyKey);
}
  1. target: 装饰的目标类的原型对象。
  2. propertyKey: 被装饰的方法的名称。
  3. descriptor: 被装饰方法的属性描述符。

场景需求,我们将装饰的目标方法重写

ts 复制代码
function MethodDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log("Method Decorator called on: ", propertyKey);

    const originalMethod = descriptor.value; // 保存原有方法

    // 重写原始方法
    descriptor.value = function(...args: any[]) {
        console.log("Method execution starts");
        const result = originalMethod.apply(this, args); // 调用原始方法
        console.log("Method execution ends");
        return result;
    };

    return descriptor;
}

其实就是简单存储原有方法,然后干一些需要自定义事情,然后再调用原来的方式,返回结果的过程。

十一、多装饰器执行顺序

  • 对于类的装饰器,执行顺序是从类的上方向下执行。
  • 而对于类的方法、属性或参数的装饰器,执行顺序是从左到右执行。

十二、有一个定义良好的顺序的装饰器应该这样做:

ts 复制代码
// 1. 类装饰器
function ClassDecorator(target: any) {
    console.log("Class Decorator");
}

// 2. 方法装饰器
function MethodDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log("Method Decorator on: ", propertyKey);
}

// 3. 属性装饰器
function PropertyDecorator(target: any, propertyKey: string) {
    console.log("Property Decorator on: ", propertyKey);
}

// 4. 参数装饰器
function ParameterDecorator(target: any, propertyKey: string, parameterIndex: number) {
    console.log("Parameter Decorator on: ", propertyKey, " with index: ", parameterIndex);
}

@ClassDecorator
class ExampleClass {
    @PropertyDecorator
    exampleProperty: string;

    @MethodDecorator
    exampleMethod(@ParameterDecorator param1: string, @ParameterDecorator param2: number) {
        console.log("Example method called");
    }
}
  1. 类装饰器:放在最上面,因为它们应用于整个类,影响类的构造函数及其行为。
  2. 方法装饰器:在类装饰器之后,因为它们应用于类的方法,可以修改方法的行为或元数据。
  3. 属性装饰器:在方法装饰器之后,因为它们应用于类的属性,可以修改属性的行为或元数据。
  4. 参数装饰器:放置在最后,因为它们应用于类的构造函数或方法的参数,可以修改参数的行为或元数据。

十三、内置装饰器

内置装饰器:TypeScript提供了一些内置的装饰器,例如

  • @deprecated: 表示废弃
  • @sealed: 表示冻结
  • @readonly: 表示只读
  • @experimental:试验性质
  • @abstract:表示抽象方法
  • ...

十四、为什么需要 reflect-metadata

reflect-metadata 提供了一种在 JavaScript 运行时获取 TypeScript 类的装饰器和类型信息的方式,使得开发者能够更灵活地处理类的元数据和类型信息,从而实现一些高级的编程模式和功能。

十五、使用装饰器库的框架和库类

  • class-transformer
  • typeorm
  • Angular
  • NestJS

十六、小结

相关推荐
濮水大叔14 小时前
在大型 Vue 项目中,如何有效管理复杂的状态?“散装版” vs “套装版”
前端·vue.js·typescript
程序员老猫1 天前
vide coding 个人产品,那就从博客开始吧
人工智能·程序员·全栈
谷哥的小弟2 天前
TypeScript数组类型
javascript·typescript
退休倒计时2 天前
【每日一题】LeetCode 199. 二叉树的右视图 TypeScript
算法·leetcode·typescript
前端之虎陈随易2 天前
编程语言级别的Skill市场,AI Agent 的未来形态
前端·vue.js·人工智能·typescript·node.js
后台开发者Ethan3 天前
类型分类、联合类型、交叉类型
typescript
鹰影473 天前
一款AI笔记助手和远程同步的markdown笔记idea-note
人工智能·笔记·rust·typescript·react
想你依然心痛3 天前
AtomCode 在前端开发中的实战体验:React + TypeScript 项目开发实录
前端·react.js·typescript
疯狂的魔鬼3 天前
精确计算容器剩余视口高度:useAutoContainerFullHeight 的工程实践
前端·css·typescript