xstate
在Angular
中可以扮演服务的角色,因此我们采取依赖注入(DI
)的方式来使用它。
流程是:创建状态机 ->
创建服务 ->
使用服务,让我们依次来实现。
创建状态机
- 新建一个状态机文件
yourMachine.ts
写入状态机
// yourMachine.ts import {Machine} from 'xstate'; export const yourMachine = Machine({ id: 'demo', initial: 'start', states:{ //... } })
创建服务
- 通过命令行工具创建模板文件:
ng s demo
服务中引入状态机器并且解析:
// 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));
使用服务
注入服务
// example.component.ts import {DemoService} from './services/demo.service'; @Component({ // .... // 1). 注入到当前组件 providers: [DemoService], } export class AppComponent{ // 2). 引入该服务 constructor(public demoSrv : DemoService) {} }
你也可以将服务注入到根组件中
在视图层渲染
<!-- 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>
调用服务中的方法
// example.component.ts gameStart() { this.demoSrv.send({type: 'start'}); } reStart() { this.demoSrv.send({type: 'reStart'}); }
使用DI
是为了维持Angular
应用的统一性,你也可以根据自己的项目选择适合的方法引入xstate
。
练习
让我们来实现一个简易红绿灯,状态:红 ->
黄 ->
绿。
参考代码:Demo-简单红绿灯
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。