所以我正在试验ngrx&通过构建以下沙箱来实现ngrx /效果:
https://stackblitz.com/edit/ngrx-vanilla
快速介绍:
三页:
问题&上下文:
收到更新后(在app / store / effects / meeting.effects.ts中说明),会调度一个新动作。
最后,问题是:让公共服务了解商店是否干净?将一个监听器注册到websocket / firebase实时数据库以便在推送数据时调度操作的最佳位置在哪里?
在这里,我做了一个效果(meeting.effects)对meetingActions.START_MEETING操作类型作出反应,每当推送数据时,都会向商店发送更新订单,但由于一系列原因,我觉得这是错误的起来:
这些案件通常如何处理?
答案 0 :(得分:5)
假设websocket
发出不同类型的事件,请将每个事件映射到websocket服务中的不同操作,例如
@Injectable()
class WebsocketService{
private socket$:Observable<Action>
getActions():Observable<Action>{
if(!this.socket$) {
this.socket$ = Observable.webSocket(url).pipe(
map(functionToMapActions)
,shareReplay(1)
);
}
return this.socket$;
}
}
其中functionToMapActions
将webSocket事件映射到操作,我建议在末尾添加shareReplay
运算符,以便我们只读取一次webSocket。
Observable.webSocket
连接到webSocket,并在事件到达时发出事件
当您怀疑webService.getActions()
您可以在@Effects
初始化see here
@Effect()
init$ = this.websocketService.getActions();
这将在您的应用程序启动后立即发出所有操作(如果在根模块中生效)或者如果模块在延迟加载模块中则加载模块;
或者,如果您对有限的一系列行动感兴趣,您可以这样做
@Effect()
init$ = this.websocketService.getActions().pipe(filter(filterNeededActionsHere));
你也可以在这样的特定事件之后开始听动作
@Effect()
init$ = this.actions$.pipe(
ofType('Event which marks start')
,swichMapTo(this.websocketService.getActions())
);
就像之前的例子一样,你也可以像以前一样过滤掉这里的行动
希望这能回答你的问题
答案 1 :(得分:2)
NgRx v9稍微更改了语法。将以下代码用于根级效果类:
init$ = createEffect(() =>
this.actions$.pipe(
ofType(ROOT_EFFECTS_INIT),
// websocket events handling logic
switchMap(() => webSocketEvents$)
)
);
这只是来自Docs的示例。
如果您使用功能级效果类,则ROOT_EFFECTS_INIT
不起作用,您需要使用OnRunEffects
生命周期挂钩:
class UserEffects implements OnRunEffects {
ngrxOnRunEffects(resolvedEffects$: Observable<EffectNotification>) {
// websocket events handling logic
return webSocketEvents$.pipe(
exhaustMap(() => resolvedEffects$)
);
}
}
更详细的示例在Docs中。
在两个示例中, webSocketEvents$
是一个Observable
,可以使用rxjs函数之一来构造它:
webSocket(socketUrl) // if you want to manage websocket connection via rxjs
fromEvent(socketIoClient) // useful if websocket connection handled by socket.io-client
答案 2 :(得分:1)
使用适配器为实体Vehicle发出不同类型事件的WebSocket定制示例
1。创建一个Vehicle-Socket-Adapter.ts
import { fromEvent, merge, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { SocketIoService } from 'src/app/shared/services/socket-io.service';
export class VehicleSocketAdapter {
public onVehicleEngineStateChange: Observable<boolean>;
constructor(vehicleId: string, private socketIoService: SocketIoService) {
//using merge from rxjs/operators to concat multiple ws events to one Observable
this.onVehicleEngineStateChange = merge(
fromEvent(this.socketIoService.socket, `event.vehicle.${vehicleId}.start`).pipe(
map(vehicleStatus => true)
),
fromEvent(this.socketIoService.socket,`event.vehicle.${vehicleId}.stop`).pipe(
map(vehicleStatus => false)
),
)
}
}
2。以后将适配器导入到您想使用的任何地方,例如app.component.ts
private subscriptions = new Subscription();
private listenForVehiclesState(vehicles) {
vehicles.forEach((vehicle) => {
const vehicleAdapter = new VehicleSocketAdapter(vehicle.id, this.webSocket);
this.subscriptions.add(
vehicleAdapter.onVehicleEngineStateChange.subscribe(vehicleStatus => {
// dispatch action when adapter commands you
this.store.dispatch(
VehiclesActions.BeginUpdateVehiclesStatusAction({
payload: {
vehicleId: vehicle.id,
status: vehicleStatus
}
})
);
}));
});
}
this.subscriptions.unsubscribe();
奖金:套接字作为服务摘要:)
import { Injectable } from '@angular/core';
import * as io from 'socket.io-client';
@Injectable({
providedIn: 'root'
})
export class SocketIoService {
public socket: SocketIOClient.Socket = io('/', { path: '/api/livedata', transportOptions: { polling: extraHeaders: {'AuthToken': 'ifAny'} }});
constructor() { }
}
快乐编码:)