在Angular中使用@ngneat/query信号时遇NG0203错误求解决
解决Angular中@ngneat/query与信号集成的NG0203错误
错误原因
你触发的NG0203错误,本质是queryResultSignal()(QueryObserver.result()内部调用的方法)必须在Angular的注入上下文(如构造函数、字段初始化器、runInInjectionContext包裹的函数)中执行,但computed的回调函数运行时并不在这个上下文范围内。你在computed里直接调用this.getProduct(...).result(),就违反了这个限制。
解决方案
这里提供两种可行的修复方式:
方案1:用runInInjectionContext包裹信号创建逻辑
通过注入Injector,将result()的调用包裹在runInInjectionContext中,确保它在合法的注入上下文里执行:
- 导入所需依赖:
import { Component, computed, inject, Injector, runInInjectionContext } from '@angular/core';
- 修改
ProductComponent代码:
export class ProductComponent { query = injectQuery(); injector = inject(Injector); // 注入Injector实例 productId = toSignal( inject(ActivatedRoute).params.pipe(map((params) => Number(params['id']))) ); product = computed(() => { const productQuery = this.getProduct(this.productId()!); // 用runInInjectionContext包裹result()调用,确保注入上下文合法 return runInInjectionContext(this.injector, () => productQuery.result()); }); getProduct(id: number) { return this.query({ queryKey: ['product', id], queryFn: () => of({ id }).pipe(delay(2 * 1000)), }); } }
方案2:使用querySignal(推荐)
@ngneat/query提供了querySignal方法,专门为Angular信号场景设计,无需手动处理注入上下文:
- 修改
getProduct方法,改用querySignal:
getProduct(id: number) { return this.query.querySignal({ queryKey: ['product', id], queryFn: () => of({ id }).pipe(delay(2000)), }); }
- 简化
computed逻辑:
product = computed(() => this.getProduct(this.productId()!));
- 模板中直接使用信号值(无需额外调用
result()):
<ng-container *ngIf="product() as product"> {{ product.data | json }} </ng-container>
完整修正后的代码示例(方案2)
import { CommonModule } from '@angular/common'; import { Component, computed, inject } from '@angular/core'; import { bootstrapApplication } from '@angular/platform-browser'; import { ActivatedRoute, RouterModule, provideRouter } from '@angular/router'; import { injectQuery } from '@ngneat/query'; import { delay, map, of } from 'rxjs'; import { toSignal } from '@angular/core/rxjs-interop'; import 'zone.js'; console.clear(); @Component({ standalone: true, selector: 'product', imports: [CommonModule], template: ` in product: <ng-container *ngIf="product() as product"> {{product.data |json}} </ng-container> `, }) export class ProductComponent { query = injectQuery(); productId = toSignal( inject(ActivatedRoute).params.pipe(map((params) => Number(params['id']))) ); product = computed(() => this.getProduct(this.productId()!)); getProduct(id: number) { return this.query.querySignal({ queryKey: ['product', id], queryFn: () => of({ id }).pipe(delay(2 * 1000)), }); } } @Component({ selector: 'app-root', standalone: true, imports: [RouterModule], template: ` <h1>Hello from {{ name }}!</h1> <a [routerLink]="['/1']">goto product 1</a> <hr> <router-outlet></router-outlet> `, }) export class App { name = 'Angular'; } bootstrapApplication(App, { providers: [provideRouter([{ path: ':id', component: ProductComponent }])], });
内容的提问来源于stack exchange,提问作者Jon You
相关产品推荐
相关产品推荐

