Angular SSR集成GraphQL与Apollo时TransferState状态无法传递到客户端
Angular SSR中TransferState结合Apollo GraphQL失效的解决方案
问题根源分析
- 客户端读取TransferState时未将结果赋值给业务变量,导致无法复用服务端数据
- Apollo查询结果结构处理错误:Apollo的
query响应包含data字段,直接断言为数组会导致数据异常 - 未同步Apollo的SSR缓存与TransferState,单纯使用TransferState无法阻止Apollo客户端重复发起请求
修正步骤
1. 修复组件内TransferState与Apollo查询逻辑
调整ngOnInit中的代码,正确处理Apollo查询结果,并确保客户端读取TransferState后赋值给业务变量:
async ngOnInit() { const myTransferStateKey = makeStateKey<any>('myDatas'); if (this.transferState.hasKey(myTransferStateKey)) { console.log('HomeComponent ngOnInit hasKey'); // 关键:将读取到的服务端数据赋值给posts this.posts = this.transferState.get(myTransferStateKey, []); this.transferState.remove(myTransferStateKey); } else { console.log('HomeComponent ngOnInit noKey'); // 正确解析Apollo查询响应的data字段 const response = await this.graphql.query({ query: this.home_query }).toPromise(); // 根据你的GraphQL查询结构调整data后的字段名(示例为posts) this.posts = response.data.posts as { capital: string; currency: string; languages: []; name: string; native: string; }[]; this.transferState.set(myTransferStateKey, this.posts); } }
2. 同步Apollo缓存与TransferState
为了彻底避免Apollo客户端重复请求,需要在服务端将Apollo缓存写入TransferState,客户端启动时从TransferState恢复缓存:
服务端Apollo配置
import { ModuleMapLoaderModule, TransferState } from '@angular/platform-server'; import { ApolloModule, APOLLO_OPTIONS } from 'apollo-angular'; import { HttpLink } from 'apollo-angular/http'; import { InMemoryCache } from '@apollo/client/core'; import { makeStateKey } from '@angular/core'; export function createApollo(httpLink: HttpLink, transferState: TransferState) { const cache = new InMemoryCache(); const stateKey = makeStateKey<any>('apollo-state'); // 服务端渲染完成后,将Apollo缓存序列化到TransferState transferState.onSerialize(stateKey, () => cache.extract()); return { link: httpLink.create({ uri: '/graphql' }), cache, }; } @NgModule({ imports: [ApolloModule, ModuleMapLoaderModule], providers: [ { provide: APOLLO_OPTIONS, useFactory: createApollo, deps: [HttpLink, TransferState], }, ], }) export class ServerApolloModule {}
客户端Apollo配置
import { ApolloModule, APOLLO_OPTIONS } from 'apollo-angular'; import { HttpLink } from 'apollo-angular/http'; import { InMemoryCache } from '@apollo/client/core'; import { TransferState, makeStateKey } from '@angular/core'; export function createApollo(httpLink: HttpLink, transferState: TransferState) { const stateKey = makeStateKey<any>('apollo-state'); const cache = new InMemoryCache(); // 从TransferState读取服务端缓存并恢复到Apollo const serverCache = transferState.get(stateKey, null); if (serverCache) { cache.restore(serverCache); } return { link: httpLink.create({ uri: '/graphql' }), cache, }; } @NgModule({ imports: [ApolloModule], providers: [ { provide: APOLLO_OPTIONS, useFactory: createApollo, deps: [HttpLink, TransferState], }, ], }) export class ClientApolloModule {}
3. 配置Apollo查询的缓存策略
在查询时设置fetchPolicy: 'cache-first',让Apollo优先读取缓存,进一步避免重复请求:
const response = await this.graphql.query({ query: this.home_query, fetchPolicy: 'cache-first' }).toPromise();
内容的提问来源于stack exchange,提问作者Redberry57
相关产品推荐
相关产品推荐

