在不使用计算或效果的情况下,不允许在“计算”或“效果”中写入信号

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

首先:抱歉我的英语不好。

我是 Angular / Signals / Zoneless 新手,我面临一个我无法弄清楚的奇怪错误。 我得到了

Writing to signals is not allowed in a 
计算的
or an
效果``

我有一个信号,它是一个对象数组,包括“id”属性和一些方法 我构建了一个 get() 函数,用于检查信号数组中的特定 id,如果存在,则返回对象,否则创建对象,将其添加到信号数组中,然后返回它

只要我不在模板中使用它,这个 get 方法就可以完美工作。 在模板中,我收到了我不明白的写作信号错误

为了在信号数组的对象上保留方法,我使用了 2 行技巧 (方法的需要阻止我使用扩展运算符):

this.table().push(newTest);
this.table.set(this.table().slice());

这是 stackblitz 上的错误:

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [JsonPipe],
  template: `
  <pre>
  Length: {{ table().length }}
  {{ get(1) | json }}
  <!-- {{ get(2) | json }}  uncomment to see the error in console-->
  </pre>
  `,
})
export class App {
  table = signal(<Test[]>[]);

  constructor() {
    this.get(1);
  }

  // look for the element in table and return it
  // if not present, create it, add it and return it
  get(id: number): Test {
    let myTest = this.table().find((elem) => elem.id == id);
    if (myTest != undefined) return myTest;
    let newTest = new Test(id);
    // the 2 next line is the only way I foound to add an object with methods in a signal array
    this.table().push(newTest);
    this.table.set(this.table().slice());
    return newTest;
  }
}

class Test {
  id: number;

  constructor(id: number) {
    this.id = id;
  }

  someMethod() {
    console.log(this.id);
  }
}

如果我用 setInterval 延迟信号设置线,它会起作用,但我确信如果我保持这样,它会产生可怕的副作用。

如果我使用没有方法的对象,则不会出现此问题,但我非常需要它们:p。我的意思是接口而不是类

angular signals
1个回答
0
投票

不是角度专家,但我的大胆猜测是,当信号在 HTML 中读取时,信号在内部使用

effect
来更新 HTML,因此当您使用
set
更新信号时,它会显示错误,因为信号内部不允许更新
effect

我认为这种方法是错误的,因为你应该在

ngOnInit
ngAfterViewInit
上准备信号数据,而不是在 DOM 中使用的方法上准备。

因此,您可以使用单独的方法

setValue
为数组的所有元素初始化值。

constructor() {
  this.setValue(1);
  this.setValue(2);
}

setValue(id: number) {
  let newTest = new Test(id);
  // the 2 next line is the only way I foound to add an object with methods in a signal array
  this.table().push(newTest);
  this.table.set(this.table().slice());
}

那么在访问信号时,你总是会得到数据,因此你可以重写 get 方法。

get(id: number): Test | undefined {
  let myTest = this.table().find((elem) => elem.id == id);
  if (myTest != undefined) return myTest;
  return undefined;
}

完整代码:

import { bootstrapApplication } from '@angular/platform-browser';
import {
  Component,
  provideExperimentalZonelessChangeDetection,
  signal,
} from '@angular/core';
import { JsonPipe } from '@angular/common';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [JsonPipe],
  template: `
  <pre>
  Length: {{ table().length }}
  {{ get(1) | json }}
  {{ get(2) | json }} 
  </pre>
  `,
})
export class App {
  table = signal(<Test[]>[]);

  constructor() {
    this.setValue(1);
    this.setValue(2);
  }

  setValue(id: number) {
    let newTest = new Test(id);
    // the 2 next line is the only way I foound to add an object with methods in a signal array
    this.table().push(newTest);
    this.table.set(this.table().slice());
  }

  // look for the element in table and return it
  // if not present, create it, add it and return it
  get(id: number): Test | undefined {
    let myTest = this.table().find((elem) => elem.id == id);
    if (myTest != undefined) return myTest;
    return undefined;
  }
}

class Test {
  id: number;

  constructor(id: number) {
    this.id = id;
  }

  someMethod() {
    console.log(this.id);
  }
}

bootstrapApplication(App, {
  providers: [provideExperimentalZonelessChangeDetection()],
});

Stackblitz 演示

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