2

xstateAngular中可以扮演服务的角色,因此我们采取依赖注入(DI)的方式来使用它。

流程是:创建状态机 -> 创建服务 -> 使用服务,让我们依次来实现。

创建状态机

  1. 新建一个状态机文件yourMachine.ts
  2. 写入状态机

    // yourMachine.ts
    import {Machine} from 'xstate';
    
    export const yourMachine = Machine({
      id: 'demo',
      initial: 'start',
      states:{
        //...
      }
    })

创建服务

  1. 通过命令行工具创建模板文件:ng s demo
  2. 服务中引入状态机器并且解析:

    // demo.service.ts
    import {OnDestroy, Injectable} from '@angular/core';
    import {fromEventPattern, Observable} from 'rxjs';
    import {map} from 'rxjs/operators'
    import {interpret} from 'xstate';
    import {yourMachine} from '../machines/yourMachine';
    
    @Injectable()
    export class DemoService implements OnDestroy {
        
      // 1). 通过interpret将状态机解析成服务
      private machineSrv = interpret(yourMachine, {devTools: true});
    
      // 2). 在机器启动后(machineSrv.onTransition().start())创建一个Observable,
      //     以便于订阅他获取实时的state对象
      state$: Observable<any> = fromEventPattern(
        (handler: any) => this.machineSrv.onTransition(handler).start(),
        (_, service) => service.stop()
      ).pipe(map(res => res[0]))
    
      // 3). 代理状态机的send方法
      send(payload): void {
        this.machineSrv.send(payload)
      }
      
    }

    state$可以根据实际生产需要进行改变,比如只在机器状态改变的时候才订阅:

     state$: Observable<any> = from(this.machineSrv).pipe(filter(state => state.changed));

使用服务

  1. 注入服务

    // example.component.ts
    import {DemoService} from './services/demo.service';
    
    @Component({
      // .... 
      // 1). 注入到当前组件
      providers: [DemoService],
    }
               
    export class AppComponent{
       // 2). 引入该服务
       constructor(public demoSrv : DemoService) {}        
    }
    你也可以将服务注入到根组件中
  2. 在视图层渲染

    <!-- example.component.html -->
    
    <!-- 使用管道async处理observable -->
    <ng-container *ngIf="demoSrv.state$ | async as state">
        <ng-container *ngIf="state.matches('start')">
          <button (click)="gameStart()">Get start!</button>
        </ng-container>
    
        <ng-container *ngIf="state.matches('end')">
          <p>Congratulations, you won!!</p>
          <button (click)="reStart()">Restart!</button>
        </ng-container>
    </ng-container>
  3. 调用服务中的方法

    // example.component.ts
    gameStart() {
        this.demoSrv.send({type: 'start'});
    }
    reStart() {
        this.demoSrv.send({type: 'reStart'});
    }

使用DI是为了维持Angular应用的统一性,你也可以根据自己的项目选择适合的方法引入xstate

练习

让我们来实现一个简易红绿灯,状态:红 ->-> 绿。

参考代码:Demo-简单红绿灯


中原大虾
123 声望3 粉丝