React JS: 如何使用 RxService 管理状态

快速使用 vite 创建一个react-ts项目

λ npm init vite@latest
npx: 6 安装成功,用时 2.033 秒
√ Project name: ... myapp
√ Select a framework: » react
√ Select a variant: » react-ts

λ cd myapp
λ npm install

下载 rxjs 和 react-rxbuilder

λ npm i rxjs react-rxbuilder

使用编辑器向 tsconfig.json 添加两项,用于支持装饰器语法和Metadata元数据

{
  "compilerOptions": {

    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,

  },
}

在根组件挂载 RxService 组件

import { RxService } from "react-rxbuilder";

ReactDOM.render(
  <React.StrictMode>

    <RxService>{() => <App />}</RxService>

  </React.StrictMode>,
  document.getElementById("root")
);

通常你只需要在你的程序中使用一次 RxService

在 App 组件中创建 Service

import { Injectable } from "react-rxbuilder";

@Injectable()
class CountService {
  i = 0;
  inc() {
    this.i++;
  }
}

使用 Injectable 将一个类快速注册为 Service

在组件中使用 CountService

function App() {
  const [countService] = useService(CountService);
  return (
    <div className="App">
      <h2>{countService.i}</h2>
      <button onClick={countService.inc}>Inc</button>
    </div>
  );
}

现在你的 App.tsx 文件应该是这样

import React from "react";
import { Injectable, useService } from "react-rxbuilder";

@Injectable()
class CountService {
  i = 0;
  inc() {
    this.i++;
  }
}

function App() {
  const [countService] = useService(CountService);
  return (
    <div className="App">
      <h2>{countService.i}</h2>
      <button onClick={countService.inc}>Inc</button>
    </div>
  );
}

export default App;

启动开发服务器,然后在页面中点击 button 看看

λ npm run dev

现在我想在点击按钮时,打印一些log信息,如何在组件中使用多个 Service ?

继续使用 Injectable 创建 LogService

@Injectable()
class LogService {
  log() {
    console.log(new Date().toLocaleString());
  }
}

然后在 App 组件中使用

function App() {
  const [countService, logService] = useService(CountService, LogService);
  return (
    <div className="App">
      <h2>{countService.i}</h2>
      <button onClick={() => (countService.inc(), logService.log())}>
        Inc
      </button>
    </div>
  );
}

现在点击按钮的同时,在控制台记录消息


为了简化代码,我们可以在 CountService 中使用 LogService

@Injectable()
class CountService {

  constructor(public readonly logService: LogService) {}

  i = 0;
  inc() {
    this.i++;
    this.logService.log();
  }
}

上面使用了 constructor 依赖注入,但是你打开服务器可能会遇到 this.logService 是 undefined 的情况,应为vite使用的是esbuild,可以使用 swc代替 esbuild

还有一种解决方案是使用静态属性代替 constructor 依赖注入

最后的代码如下

import React from "react";
import { Injectable, useService } from "react-rxbuilder";
import "reflect-metadata";

@Injectable()
class LogService {
  static ins: LogService;
  log() {
    console.log(new Date().toLocaleString());
  }
}

@Injectable()
class CountService {
  readonly logService = LogService.ins;
  
  i = 0;
  inc() {
    this.i++;
    this.logService.log();
  }
}

function App() {
  const [countService] = useService(CountService);
  return (
    <div className="App">
      <h2>{countService.i}</h2>
      <button onClick={countService.inc}>Inc</button>
    </div>
  );
}

export default App;
上一篇:设计模式 --kkb


下一篇:使用回调