1. 程式人生 > 其它 >React JS: 如何使用 RxService 管理狀態

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;