Angular 19,动态变化的数组的 WriteableSignal

问题描述 投票:0回答:1

我在服务中有一个可写信号:

private errorEntries: WritableSignal<ErrorEntry[]> = signal<ErrorEntry[]>([])

我有一个吸气剂在服务中:

  getErrorEntries(): WritableSignal<ErrorEntry[]> {
    return this.errorEntries;
  }

和阳极法:

  public addError(error: any): void {
    const timestamp = new Date().toISOString();
    const message = error.message || error.toString();
    const stack = error.stack || 'No stack trace available';
    const route = this.router.url;

    const errorEntry: ErrorEntry = { timestamp, message, stack, route };
    this.errorEntries.update((entries) => [...entries, errorEntry]);
  }

我在另一个组件中有效果。

  showExclamationMark = false;

  constructor(private globalErrorHandlerService: GlobalErrorHandlerService) {
    effect(() => {
      const errors = this.globalErrorHandlerService.getErrorEntries()();
      this.showExclamationMark = errors.length > 0;
    });
  }

效果很好。但errors.length总是为空,为什么? 我没有看到我错过了什么。

我在服务调试期间注意到 errorEntries 属性之一 有一个值:

  SYMBOL(Signal): 
    value: Array(1)

包含一个值。

angular signals
1个回答
0
投票

建议以下改进。

我们可以用

_
来定义私有变量。

private _errorEntries: WritableSignal<ErrorEntry[]> = signal<ErrorEntry[]>(
  []
);

我们可以将 getter 设为

asReadonly
信号,因为该方法似乎只修改信号。

get errorEntries(): Signal<ErrorEntry[]> {
  return this._errorEntries.asReadonly();
}

那么对于您的场景,您实际上并不需要

effect
(因为它们不适用于副作用/DOM 更新),但您的场景是原始状态的派生状态。所以更好的解决方案是使用
computed
来计算。

showExclamationMark = computed(() =>
  this.globalErrorHandlerService.errorEntries().length > 0 ? '!' : ''
);

完整代码:

import {
  Component,
  Injectable,
  inject,
  WritableSignal,
  signal,
  Signal,
  effect,
  computed,
} from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';

export interface ErrorEntry {
  timestamp: string;
  message: string;
  stack: string;
  route: string;
}

@Injectable({
  providedIn: 'root',
})
export class GlobalErrorHandlerService {
  private _errorEntries: WritableSignal<ErrorEntry[]> = signal<ErrorEntry[]>(
    []
  );

  get errorEntries(): Signal<ErrorEntry[]> {
    return this._errorEntries.asReadonly();
  }

  public addError(error: any): void {
    const timestamp = new Date().toISOString();
    const message = error.message || error.toString();
    const stack = error.stack || 'No stack trace available';
    const route = '';

    const errorEntry: ErrorEntry = { timestamp, message, stack, route };
    this._errorEntries.update((entries) => [...entries, errorEntry]);
  }
}

@Component({
  selector: 'app-root',
  template: `
    {{showExclamationMark()}}
  `,
})
export class App {
  name = 'asedf';
  showExclamationMark = computed(() =>
    this.globalErrorHandlerService.errorEntries().length > 0 ? '!' : ''
  );

  constructor(private globalErrorHandlerService: GlobalErrorHandlerService) {}

  ngOnInit() {
    this.globalErrorHandlerService.addError(new Error('adsfasdf'));
  }
}

bootstrapApplication(App);

Stackblitz 演示

© www.soinside.com 2019 - 2024. All rights reserved.