1.6.1 • Published 2 years ago

ajanuw-react-rxservice v1.6.1

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

react-rxservice

Use dependency injection to create services, inspired by Angular

Install

$ npm i ajanuw-react-rxservice
$ npm i rxjs

如果你想使用constructor依赖注入

$ npm i reflect-metadata

配置 tsconfig.json

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
  },
}

全局服务

创建全局服务

@Injectable()
class AppService {
  i = 0;
}

@Injectable 立即注册一个全局服务,当数据变化时通知订阅者

订阅全局服务

export default memo(() => {
  const [as] = useService(AppService);

  return (
    <RxService
      builder={() => {
        return (
          <div>
            <p>{as.i}</p>
            <button onClick={() => as.i++}>change</button>
          </div>
        );
      }}
    />
  );
});

RxService 组件会自动订阅全局服务,收到响应时触发更新

局部服务(非全局服务)

创建局部服务

@Injectable({ global: false })
class PS implements ServiceProxy {
  i = 0;
  
  OnCreate() {}
  OnUpdate() {}
  OnDestroy() {}
}

使用Injectable时可以传入一些配置项,将global设置为false注册为局部服务,并且不会立即注册

提供了一些钩子函数,用于监听局部服务的生命周期

订阅局部服务

export default memo(() => {
  const [ps] = useService(PS);

  return (
    <RxService
      services={[PS]}
      global={false}
      builder={() => {
        return (
          <div>
            <p>{ps.i}</p>
            <button onClick={() => ps.i++}>change</button>
          </div>
        );
      }}
    />
  );
});

使用useService时初始化局部服务

RxServiceservices属性用于添加局部服务,global设置为fasle将不会订阅全局服务,如果你需要局部服务并且也需要全局服务可以无视此选项

RxService 被销毁时,services中的所有局部服务也会自动销毁,销毁前会调用 OnDestroy

OnCreate 在组件渲染完成之前触发

其他问题

不想监听服务中的某个属性的变更?

  1. 使用@Ignore装饰器

    @Injectable({ global: false })
    class PS implements ServiceProxy {
    
      @Ignore()
      ref_ = React.createRef<any>();
    }
    1. 使用autoIgnore配置选项,会自动无视以_结尾的属性
    @Injectable({ global: false, autoIgnore: true })
    class PS implements ServiceProxy {
      ref_ = React.createRef<any>();
    }

在服务中使用其它服务?

  1. 使用constructor依赖注入

    import "reflect-metadata";
    
    @Injectable()
    class UserinfoService {}
    
    @Injectable()
    class AppService {
      constructor(public readonly userinfo: UserinfoService) {}
    }
  2. 使用静态属性

    @Injectable()
    class UserinfoService {
      static ins: UserinfoService;
    }
    
    @Injectable()
    class AppService {
      userinfo = UserinfoService.ins;
      i = 0;
    }
  3. 使用@Late装饰器

    @Injectable({ id: "UserinfoService" })
    class UserinfoService {
      i = 0;
    }
    
    @Injectable()
    class AppService {
      @Late("UserinfoService")
      userinfo!: UserinfoService;
    
      @Late("AfterService")
      after!: any;
    }
    
    @Injectable({ id: "AfterService" })
    class AfterService {}

    @Late装饰器需要提供一个服务的唯一id,如果这个服务已经被初始化则会立即初始化属性(userinfo),否则会一直等到服务初始化时才设置属性(after)

  4. 在组件中使用多个服务?

    @Injectable()
    class UserinfoService {}
    
    @Injectable()
    class AppService {}
    
    @Injectable({ global: false })
    class PS {}
    
    export default memo(() => {
      const [ps, as, us] = useService(PS, AppService, UserinfoService);
      return (
        <RxService
          services={[PS]}
          builder={() => {
            return <div></div>;
          }}
        />
      );
    });

使用上一次销毁的数据?

只能在局部服务中在这样做!

@Injectable({ global: false })
class PS implements ServiceProxy {
  i = 0;
  OnDestroy() {
    return true;
  }
}

如果在页面销毁时i=10,并且在OnDestroy钩子中返回true,那么下次重启这个服务时,数据不会被初始化而是继续使用上一次的数据,再次进入页面你会直接看到i=10而不是i=0

服务从第一次创建就一直存在于内存中,销毁只是一个状态,在销毁状态下所有的变更都不会通知订阅者

当再次启动销毁状态的服务时,只是取消了销毁状态,数据的初始化取决于上一次OnDestroy钩子的返回值,如果返回true将继续使用以前的数据,否则会重新初始化一个实例,并创建一个新的代理然后触发OnCreate钩子

改变数据时,不想通知订阅者?

@Injectable()
class PS {
  i = 0;

  add() {
    noreact(() => {
      this.i++
    })
  }
}

noreact的钩子函数中,改变数据时不会通知订阅者

作为装饰器使用也可以达到同样的效果

@Injectable()
class PS {
  i = 0;

  @noreact()
  add() {
    this.i++
  }
}

监听属性的变更

  1. Watch 装饰器,监听一个或多个属性的变更
class PS {
  i = 0;
  obj = { i: 0 }

  @Watch(['this.i', 'this.obj.i'])
  watch(newVal: number, oldVal: number, key: string) {
    console.log(key, newVal, oldVal);
  }
}
  1. AutoWatch 自动监听属性变化
class PS implements ServiceProxy {
  i = 0;
  j = 0;

  @AutoWatch()
  watch() {
    this.j = this.i * 2
  }
}

会自动代理哪些对象?

  • Array
  • [object Object]
  • [object Set]
  • [object Map]
  • [object WeakMap]

Run test

$ npm start
$ npm t
1.6.1

2 years ago

1.6.0

3 years ago

1.5.1

3 years ago

1.5.0

3 years ago

1.4.0

3 years ago

1.3.0

3 years ago

1.2.0

3 years ago

1.1.2

3 years ago

1.1.1

3 years ago

1.1.0

3 years ago

1.0.7

3 years ago

1.0.6

3 years ago

1.0.2

3 years ago

1.0.5

3 years ago

1.0.4

3 years ago

1.0.3

3 years ago

1.0.1

3 years ago

1.0.0

3 years ago

0.8.0

3 years ago

0.7.0

3 years ago

0.6.1

3 years ago

0.6.0

3 years ago

0.5.1

3 years ago

0.3.0

3 years ago

0.2.0

3 years ago

0.5.0

3 years ago

0.4.1

3 years ago

0.4.0

3 years ago

0.1.1

3 years ago

0.1.0

3 years ago