javascript - Varför ändras inte observable-resultatet när man använder push/splice på en array


Jag har en tjänst som denna:

export class ArrService {
  private arr: any[] = [1,2,3];

  constructor() {}

  setValue(index: number, value: number): void {
    this.arr[index]= value;
  }

  addItem(value: any): void {
    this.arr.push(element);
  }

  removeItem(index: number): void {
    this.arr.splice(index, 1);
  }

  getItems(): Observable<any> {
    return of(this.arr);
  }
}

och jag prenumererar på getItems()-observablet i min komponent för mitt vidare syfte:

this.arrService.getItems().subscribe(res => {
  this._arr = res;
});

All action sker direkt genom att kalla funktionen i ArrService. När jag kallade setValue() ändrades både källarrayen i ArrService och den lokala arrayen i komponenten. Och jag noterar att observablen inte emitterade igen vid förändring, så jag antar att observablerna bör passeras som referens.

Men när jag kallade addItem() och removeItem(), ändrades källan, men det lokala gjorde det inte. Så observablen skickas inte som referens? Eller missförstår jag hur observable fungerar?

Jag vet att ämnet eller beteendeÄmnet kan slutföra min tjänst. Men jag vill veta hur observabeln fungerar i detta fall, varför vissa åtgärder följs men vissa inte.

Svar #1

Prova Subject

export class ArrService {
  private arr: any[] = [1,2,3];
  private arr$ = new Subject();

  constructor() {}

  setValue(index: number, value: number): void {
    this.arr[index]= value;
    this.arr$.next(this.arr);
  }

  addItem(value: any): void {
    this.arr.push(element);
    this.arr$.next(this.arr);
  }

  removeItem(index: number): void {
    this.arr.splice(index, 1);
    this.arr$.next(this.arr);
  }

  getItems(): Observable<any> {
    return this.arr$.asObservable();
  }
}

Använd BehaviorSubject om du vill behålla det senaste emitterade värdet (användbart i fall när du prenumererar efter att du har emitterat värde med .next())


När du arbetar med arrayer finns det alltid problem kopplade till att övervaka alla förändringar som har gjorts i dem. Du kommer att stöta på liknande beteende på andra ställen i Angular också, där om du lägger till ett nytt värde i en array, kommer varken "ngOnChange" eller till och med "zone.js" att upptäcka någon värdeförändring. I sådana fall måste du antingen skapa en ny arrayreferens eller hantera det manuellt.

Svar #2

Ett ämne är en typ av observerbar. Som sådan är det ett flöde. Du kan lägga till ett objekt (som ett nummer) till flödet och objektet kommer att sändas till alla observatörer av flödet.

private arr = new Subject<any[]>();

Eller om du behöver standardvärde:

private arr = new BehaviorSubject<any[]>([1,2,3]);

utlösa händelse i setValue på detta sätt:

  setValue(index: number, value: number): void {
    this.arr.next(value);
  }

ändra getItems på detta sätt:

  getItems(): Observable<any> {
    return this.arr.asObservable();
  }

Slutresultat:

@Injectable()
export class ArrService {
  private arr = new BehaviorSubject<any[]>([1,2,3]);

  constructor() {}

  setValue(index: number, value: number): void {
    let tst = this.arr.value;
    tst.push(value);
    this.arr.next(tst);
  }


  getItems(): Observable<any> {
    // return of(this.arr);
    return this.arr.asObservable();
  }
}