我有一个 Angular 7 应用程序,包含大约 30 个模块。我正在
app.component.ts
中获取用户详细信息,以便在整个应用程序中使用它,但我突然注意到用户详细信息 API 在 1 次加载时运行多次。
将日志放入
ngOnInit()
中的 app.component.ts
中后,我发现日志会打印多次,但仅发生在浏览器上的服务器端渲染上,它仅渲染一次。
知道为什么
ngOnInit()
多次打电话吗?
Angular SSR 的概念是,在第一次加载页面/URL 时,它通过服务器呈现,然后在客户端传输数据。因此从技术上讲,它会调用所有组件,服务在该页面/URL 上存在两次。
您可以使用条件 isPlatformBrowser 和 isPlatformServer 方法,这样您就可以在服务器端仅渲染所需的部分。我们只在 SSR 上渲染与 SEO 优化相关的特定内容。
ngOnInit() 在所有指令实例化后仅挂钩一次。如果您在 ngOnInit() 内有订阅并且未取消订阅,那么如果订阅的数据发生更改,它将再次运行。在您的情况下,当通过服务器端的 SSR 加载 API 调用时,服务器并不总是等待响应的到来,这可能是多个日志的原因。建议使用 isPlatformBrowser 将其委托给客户端。这是我根据对一般 SSR 流程的调查得出的结果。
我不确定这个问题是否已经解决,但这里有一个建议:
在组件本身中添加
subscribe
部分,并将其从进行 HTTP 调用的函数中删除:
ngOnInit() {
this.loadData();
}
loadData(){
this.my_service.getData().subscribe(data => this.userDetails = data);
}
在您的服务中,您可以进行普通的 HTTP 调用:
getData() {
return this.http.get('../your/url')
.map((res:Response) => res.json());
}
我希望这有帮助。
在除 afterRender 和 afterNextRender 之外的 SSR 中,构造函数和初始生命周期挂钩将在服务器和浏览器中执行。
我们可以对httpClient调用实现缓存,以避免多次api调用。
bootstrapApplication(AppComponent, { providers: [ provideClientHydration(withHttpTransferCacheOptions({ includePostRequests: true })) ] });
或者我们可以使用 PLATFORM_ID 与 isPlatformBrowser 和 isPlatformServer 来识别它是在服务器还是客户端中渲染
import { PLATFORM_ID } from '@angular/core';
import { isPlatformBrowser, isPlatformServer } from '@angular/common';
ngOnInit(): void {
if(isPlatformBrowser(this.platformId)){
// runs on client / browser
console.log("from browser.");
}
if(isPlatformServer(this.platformId)){
// runs on server / node
console.log("from server");
}
}