Angular 19+中如何使用Signals在重新计算时缓存查询结果?
Angular 19+中如何使用Signals在重新计算时缓存查询结果?
我完全懂你现在的需求:基于组件状态动态生成一批查询,希望这些查询的结果能被智能缓存——只有第一次遇到这个查询时才发起请求,之后不管组件状态怎么变导致查询列表重新计算,只要是同一个查询就直接用缓存好的结果,还得支持用户手动刷新对吧?
在Angular 19+里,结合Signals和rxResource(或者新出的resource API)来实现这个需求特别顺手,我给你两个实用的落地方案:
方案一:自定义缓存Map+计算信号,完全掌控缓存逻辑
先搞一个全局的缓存Map来存每个查询的结果,再用计算信号判断什么时候该发起请求:
import { computed, signal, inject } from '@angular/core'; import { ResourceService, rxResource } from '@angular/core/rxjs-interop'; @Component({ selector: 'app-query-list', standalone: true, template: ` <div *ngFor="let query of queries()"> <div *ngIf="getQueryResult(query) as result"> @if (result.loading) { 加载中... } @else { {{ result.data }} <button (click)="refreshQuery(query)">刷新结果</button> } </div> </div> ` }) export class QueryListComponent { // 组件状态信号,用来动态生成查询条件 componentState = signal({ filter: 'active', page: 1 }); // 根据状态生成查询列表的计算信号 queries = computed(() => { const state = this.componentState(); // 这里根据你的业务逻辑生成具体查询数组,比如不同参数组合 return [ { endpoint: '/api/data', params: { type: 'A', ...state } }, { endpoint: '/api/data', params: { type: 'B', ...state } } ]; }); // 缓存Map,用查询的唯一标识当key private queryCache = new Map<string, any>(); private resourceService = inject(ResourceService); // 获取单个查询结果的计算信号 getQueryResult = computed((query) => { // 生成唯一缓存key,比如把endpoint和参数转成字符串 const cacheKey = JSON.stringify(query); // 缓存存在就直接返回 if (this.queryCache.has(cacheKey)) { return { data: this.queryCache.get(cacheKey), loading: false, isCached: true }; } // 没缓存就发起请求 const resource = rxResource({ source: () => this.resourceService.get(query.endpoint, { params: query.params }), initialValue: { data: null, loading: true } }); // 请求完成后更新缓存 resource.value.subscribe({ next: (data) => { this.queryCache.set(cacheKey, data); } }); return { data: resource.value(), loading: false, isCached: false }; }); // 手动刷新指定查询的方法 refreshQuery(query: any) { const cacheKey = JSON.stringify(query); this.queryCache.delete(cacheKey); // 触发计算信号重新计算,重新发起请求 this.queries.set(this.queries()); } }
这个方案的好处是逻辑完全可控,你可以随便调整缓存的过期、清理规则。需要注意的是,生成cacheKey时要确保唯一性,避免不同查询被误判成同一个。
方案二:利用resource API内置缓存,简洁省心
Angular 19+的resource API本身就带了缓存能力,只要简单配置就能实现需求:
import { computed, signal, inject } from '@angular/core'; import { resource, ResourceService } from '@angular/core/rxjs-interop'; @Component({ selector: 'app-query-list', standalone: true, template: ` <div *ngFor="let query of queries()"> <div> @if (getQueryResource(query).loading) { 加载中... } @else { {{ getQueryResource(query()).data }} <button (click)="getQueryResource(query).refresh()">刷新</button> } </div> </div> ` }) export class QueryListComponent { componentState = signal({ filter: 'active', page: 1 }); queries = computed(() => { const state = this.componentState(); return [ { uniqueId: 'query-type-A', endpoint: '/api/data', params: { type: 'A', ...state } }, { uniqueId: 'query-type-B', endpoint: '/api/data', params: { type: 'B', ...state } } ]; }); private resourceService = inject(ResourceService); // 为每个查询创建带缓存的resource getQueryResource = computed((query) => { return resource({ source: () => this.resourceService.get(query.endpoint, { params: query.params }), initialValue: null, // 配置缓存:用查询的唯一ID当缓存key,默认永久有效 cache: { key: query.uniqueId, // 要是想加过期时间,就加这行:expiresIn: 3600000(1小时) } }); }); }
这个方案更简洁,因为resource已经帮你封装了缓存逻辑,连手动刷新的方法都给你准备好了。核心就是给每个查询分配唯一的uniqueId作为缓存key,只要这个ID不变,就算查询列表重新计算,也会直接复用缓存结果。
几个注意点
- 如果查询参数很复杂,生成缓存key的时候可以用专门的哈希工具(比如
object-hash库),比JSON.stringify更稳定。 - 要是需要全局共享缓存,可以把缓存Map或者
resource的缓存配置放到单独的服务里,这样多个组件能共用同一份缓存。 - 手动刷新时,记得要么清除对应缓存(方案一),要么调用
resource的refresh()方法(方案二),才能触发重新请求。
内容来源于stack exchange
相关产品推荐
相关产品推荐

