我遇到了这个错误expression has changed after it was checked
。我知道这个检查只在开发模式下运行(运行两次),并且在生产模式下不会出现这个错误信息。但我想知道为什么会这样。
我有一个基于信号的加载器服务,如下所示:
import { Injectable, signal } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class LoaderService {
private _isLoading = signal<boolean>(false);
get isLoading(): boolean {
return this._isLoading();
}
show() {
this._isLoading.update(() => true);
}
hide() {
this._isLoading.update(() => false);
}
}
我也有这个拦截器:
import {
HttpEvent,
HttpHandler,
HttpInterceptor,
HttpRequest,
HttpResponse,
} from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, catchError, map, throwError } from 'rxjs';
import { USE_LOADING_SPINNER } from '../constants/app.constants';
import { LoaderService } from '../../shared/services/loader.service';
@Injectable()
export class LoadingInterceptor implements HttpInterceptor {
constructor(private loaderService: LoaderService) {}
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
if (req.context.get(USE_LOADING_SPINNER)) this.loaderService.show();
return next.handle(req).pipe(
map((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) this.loaderService.hide();
return event;
}),
catchError((error) => {
this.loaderService.hide();
return throwError(() => error);
})
);
}
}
始终设置USE_LOADING_SPINNER
为 true,这意味着我只需标记那些我不想有任何加载指示器的请求。
由于LoaderService
是基于信号的,因此我effect
在组件的构造函数中注册了一个,如下所示:
constructor() {
effect(() => {
this.loading = this.loaderService.isLoading;
});
}
请注意,该loading
变量不是信号,而是一个纯布尔变量,因为该isLoading
方法返回布尔值,而不是信号。
在模板中,我在网格组件中有这个:
[loading]="loading"
此设置正在运行,初始路由时会显示加载指示器。
现在我向组件添加一个刷新方法,如下所示:
refresh() {
//this.loaderService.show();
this.gridData$ = this.userService.getUsers();
//.pipe(tap(() => this.loaderService.hide()));
}
但是,如果我点击刷新,主题标题就会报错,而且加载指示器也没有显示。拦截器被触发了,我检查了一下。
但如果我取消注释对它的调用,loaderService
它就会按预期工作。
为什么我会收到这个错误?
我希望您能理解在通常的“错误设置”情况下该错误的含义。
就你的情况而言,你很可能有一个标记
要解决这个问题,你应该将代码转换为在事件处理期间执行 http 调用,而不是在模板执行期间。例如通过 rxjs
我认为错误可能是由于视图初始化后
expression has changed after it was checked
更新造成的。建议尝试基于信号的更新,这样可能根本不会触发此错误。loading
我认为这是由于
getter
和的使用不当造成的signal
,而不是在服务级别执行信号,而是返回实际的信号。当您想对之前的状态执行某些操作时,请使用
update
,否则设置是更好的选择。您的信号是私有的,您只想返回信号的只读版本,因此我们使用它
asReadonly()
来删除可写操作set
以及update
组件何时使用此信号。现在,在组件级别,
effect
只需将服务属性分配给组件属性,而不是过度杀伤。在模板级别,执行信号。