Angular 5.2.10 TransferState页面重复加载(闪烁)问题咨询
解决Angular 5.2.10 TransferState导致的页面闪烁问题
嘿,我之前也碰到过一模一样的Angular Universal闪烁问题!本质原因就是服务端渲染出的内容,在客户端初始化时没有复用服务端已经获取的数据,反而重新发起了HTTP请求,才会出现“先显示服务端内容、随后消失再加载客户端内容”的闪烁情况。下面是一步步的排查和修复方案:
1. 给你的数据服务补上TransferState的核心逻辑
首先要确保在数据请求前,先判断环境(服务端/浏览器端),并正确读写TransferState的缓存。先把你的服务代码补全优化:
import { Injectable, Inject, PLATFORM_ID } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { TransferState, makeStateKey } from '@angular/platform-browser'; import { isPlatformBrowser, isPlatformServer } from '@angular/common'; import { Observable } from 'rxjs/Observable'; import "rxjs/add/operator/map"; import "rxjs/add/observable/of"; // 创建唯一的State Key,用来标记缓存的数据(建议根据业务命名,比如'product-list-data') const DATA_CACHE_KEY = makeStateKey<any>('your-unique-data-key'); @Injectable() export class YourDataService { constructor( private http: HttpClient, private transferState: TransferState, @Inject(PLATFORM_ID) private platformId: Object ) {} fetchData() { // 浏览器端优先读缓存 if (isPlatformBrowser(this.platformId)) { const cachedData = this.transferState.get(DATA_CACHE_KEY, null); if (cachedData) { // 拿到缓存后记得移除,避免后续路由复用旧数据 this.transferState.remove(DATA_CACHE_KEY); return Observable.of(cachedData); } } // 没缓存就发起请求 return this.http.get('your-api-endpoint-url') .map(response => { // 服务端请求完成后,把数据存入TransferState if (isPlatformServer(this.platformId)) { this.transferState.set(DATA_CACHE_KEY, response); } return response; }); } }
2. 检查AppModule和ServerModule的配置是否正确
这一步很容易漏!必须在两端的模块里分别导入对应的TransferState模块:
- 浏览器端AppModule:
import { BrowserModule, BrowserTransferStateModule } from '@angular/platform-browser'; @NgModule({ imports: [ BrowserModule.withServerTransition({ appId: 'your-app-unique-id' }), BrowserTransferStateModule, // 必须加这个! // 其他你的模块... ] }) export class AppModule {}
- 服务端ServerModule:
import { ServerModule, ServerTransferStateModule } from '@angular/platform-server'; @NgModule({ imports: [ AppModule, ServerModule, ServerTransferStateModule, // 必须加这个! // 其他你的模块... ] }) export class AppServerModule {}
3. 避免组件/路由守卫重复发起请求
如果你的页面数据是通过路由守卫(比如Resolve)获取的,一定要让守卫复用上面的服务逻辑,不要在组件的ngOnInit里再重复调用请求。举个路由守卫的例子:
@Injectable() export class DataResolveGuard implements Resolve<any> { constructor(private dataService: YourDataService) {} resolve(route: ActivatedRouteSnapshot) { // 直接用服务的fetchData方法,自动走TransferState逻辑 return this.dataService.fetchData(); } }
然后在路由配置里绑定这个守卫,确保服务端渲染时提前拉取数据并存入缓存。
4. 排查第三方库或DOM操作导致的额外渲染
有些第三方UI库(比如某些图表、富文本组件)会在客户端初始化时直接替换服务端渲染的DOM节点,也会导致闪烁。可以先暂时移除这类库测试,如果闪烁消失了,就需要找对应库的SSR兼容方案,或者在客户端初始化时判断是否已有服务端渲染的节点再做处理。
内容的提问来源于stack exchange,提问作者Patryk Panek
相关产品推荐
相关产品推荐

