从 Electron Container IPC Channel 接收数据时,变更检测会间歇性工作
Change Detection works intermittently when receiving data from Electron Container IPC Channel
我有一个应用程序正在侦听来自 IPC 渲染器通道的传入数据。这是我的设置:
将数据发送到 angular 应用程序(mainWindow)的容器:
mainWindow.loadURL('http://www.myangularapp.com') //where the angular app lives (example url).
mainWindow.webContents.on('did-finish-load', () => {
const data = { name: "John Doe", address: "123 Main St", city: "NY"}
mainWindow.webContents.send('data-from-container', data)
}
})
angular 应用程序:
constructor(
private store: Store<fromStore.AppState>,
private cd: ChangeDetectorRef,
private zone: NgZone,
) {}
ngOnInit() {
this.isLoading = true;
if (this.electronService.ipcRenderer) {
this.electronService.ipcRenderer.on('data-from-container', (event, data) => {
this.zone.run(() => {
if(data){
setTimeout(() => {
console.log(data) // verified data is always received
this.formData = data; // property that form uses to populate data in the dom
this.prepopulateForm(data) // method that places incoming data in ngrx store
}, 1000)
}
})
})
}
this.store.select('containerData').subscribe(data => {
setTimeout(()=> {
console.log(data) // data is always being set in ngrx
this.isLoading = false
}, 5000);
})
}
每次 IPC 通道发出 'data-from-container' 事件时,总是从我的 OnInit 调用接收到数据,但数据并不总是在我的表单中设置!我注意到的模式通常是,当 angular 应用程序首次在容器内启动时,数据不会预填充表单,在初始启动后,每次后续应用程序启动时,数据都会出现。
我已经尝试使用 ngZone、setTimeout 和 detectChange 方法来触发更改检测,因此 Angular 应用程序可以检测到新设置的 formData,但它并没有始终如一地预填充表单。关于如何解决这个问题有什么建议吗?
我对电子有非常基本的了解,所以我会尝试向您展示这个想法。对我来说,你的问题来自视图的初始化。您不会丢失事件,因为您可以在控制台中看到它们,但在视图中看不到,这加强了我的猜测。
如您的代码所示,您只发送一个事件(我想这只是为了测试理由),我们希望在呈现视图时显示它。
在您的组件中添加一个主题,通知我们视图已初始化,例如:
import { Subject, combineLatest, fromEvent } from 'rxjs';
viewInitialized$ = new Subject();
...
ngAfterViewInit() {
this.viewInitialized$.next();
}
...
现在我们可以等待两个发射的到来,一个来自 ipcRenderer
,另一个来自 viewInitialized$
,使用 combineLatest
运算符。
在此之前,我们必须将 ipcRenderer
转换为 Observable
。从这个 响应我们可以 fromEvent(ipcRenderer,'data-from-container')
。如果它不起作用,我们可以使用另一个主题,每次我们在 ipcRenderer.on()
中收到某些内容时都会发出事件,第二个解决方案需要 ngZone。
ngOnInit() {
...
const containerData$ = fromEvent(this.electronService.ipcRenderer, 'data-from-container');
this.subscription = combineLatest(containerData$, this.viewInitialized$).subscribe(combined => {
const data = combined[0];
this.formData = data;
this.prepopulateForm(data)
})
...
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
希望对您有所帮助。
我有一个应用程序正在侦听来自 IPC 渲染器通道的传入数据。这是我的设置:
将数据发送到 angular 应用程序(mainWindow)的容器:
mainWindow.loadURL('http://www.myangularapp.com') //where the angular app lives (example url).
mainWindow.webContents.on('did-finish-load', () => {
const data = { name: "John Doe", address: "123 Main St", city: "NY"}
mainWindow.webContents.send('data-from-container', data)
}
})
angular 应用程序:
constructor(
private store: Store<fromStore.AppState>,
private cd: ChangeDetectorRef,
private zone: NgZone,
) {}
ngOnInit() {
this.isLoading = true;
if (this.electronService.ipcRenderer) {
this.electronService.ipcRenderer.on('data-from-container', (event, data) => {
this.zone.run(() => {
if(data){
setTimeout(() => {
console.log(data) // verified data is always received
this.formData = data; // property that form uses to populate data in the dom
this.prepopulateForm(data) // method that places incoming data in ngrx store
}, 1000)
}
})
})
}
this.store.select('containerData').subscribe(data => {
setTimeout(()=> {
console.log(data) // data is always being set in ngrx
this.isLoading = false
}, 5000);
})
}
每次 IPC 通道发出 'data-from-container' 事件时,总是从我的 OnInit 调用接收到数据,但数据并不总是在我的表单中设置!我注意到的模式通常是,当 angular 应用程序首次在容器内启动时,数据不会预填充表单,在初始启动后,每次后续应用程序启动时,数据都会出现。
我已经尝试使用 ngZone、setTimeout 和 detectChange 方法来触发更改检测,因此 Angular 应用程序可以检测到新设置的 formData,但它并没有始终如一地预填充表单。关于如何解决这个问题有什么建议吗?
我对电子有非常基本的了解,所以我会尝试向您展示这个想法。对我来说,你的问题来自视图的初始化。您不会丢失事件,因为您可以在控制台中看到它们,但在视图中看不到,这加强了我的猜测。
如您的代码所示,您只发送一个事件(我想这只是为了测试理由),我们希望在呈现视图时显示它。
在您的组件中添加一个主题,通知我们视图已初始化,例如:
import { Subject, combineLatest, fromEvent } from 'rxjs';
viewInitialized$ = new Subject();
...
ngAfterViewInit() {
this.viewInitialized$.next();
}
...
现在我们可以等待两个发射的到来,一个来自 ipcRenderer
,另一个来自 viewInitialized$
,使用 combineLatest
运算符。
在此之前,我们必须将 ipcRenderer
转换为 Observable
。从这个 fromEvent(ipcRenderer,'data-from-container')
。如果它不起作用,我们可以使用另一个主题,每次我们在 ipcRenderer.on()
中收到某些内容时都会发出事件,第二个解决方案需要 ngZone。
ngOnInit() {
...
const containerData$ = fromEvent(this.electronService.ipcRenderer, 'data-from-container');
this.subscription = combineLatest(containerData$, this.viewInitialized$).subscribe(combined => {
const data = combined[0];
this.formData = data;
this.prepopulateForm(data)
})
...
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
希望对您有所帮助。