【问题标题】:BehaviorSubject behaves diffent with string and an objectBehaviorSubject 的行为与字符串和对象不同
【发布时间】:2020-03-09 10:29:19
【问题描述】:

我尝试在 ionic/angular 项目中使用数据服务来跨组件共享数据,但该服务无法按我预期的方式处理对象。

在一个组件(即:父组件)中,当从订阅服务获取属性值的本地对象的值发生更改时,它会将值传播到其他组件,但我认为如果该值是通过使用 next() 的服务进行更改。

下面是一个空白离子项目中的最小示例,用于比较此场景中的字符串和对象。在父组件中有两种方法,一种是更改本地值(发生问题的地方是对象而不是字符串),另一种是通过服务更改值(按预期工作)。

我可能做错了什么,behaviourSubject 以这种方式与对象一起工作还是有问题?

data.service.ts

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class DataService {

  private strSrc = new BehaviorSubject('default');
  readonly strCurr = this.strSrc.asObservable();

  private objSrc = new BehaviorSubject({ name : 'Default' });
  readonly objCurr = this.objSrc.asObservable();

  constructor() { }

  chgStr(strNew) {
    this.strSrc.next(strNew);
  }

  chgObj(objNew) {
    this.objSrc.next(objNew);
  }
} 

child.component.ts

import { Component, OnInit } from '@angular/core';
import { DataService } from '../../service/data.service';

@Component({
  selector: 'app-child',
  template: `
  <p>child data String: {{ str }}</p>
  <p>child data Object: {{ obj.name }}</p>
  `
})

export class ChildComponent implements OnInit {
  str: string;
  obj: { name: string };

  constructor(private data: DataService) { }

  ngOnInit() {
    this.data.strCurr.subscribe(data => this.str = data);
    this.data.objCurr.subscribe(data => this.obj = data);
  }
}

home.page.ts

import { Component, OnInit } from '@angular/core';
import { DataService } from '../service/data.service';

@Component({
  selector: 'app-home',
  template: `<ion-content>
  <p>parent data String: {{ str }}</p>
  <p>parent data Object: {{ obj.name }}</p>
  <br/>
  <app-child></app-child>
    <ion-button (click)="chgLocal()">
      change parent variable
    </ion-button>
    <ion-button (click)="chgBehaviorSubject()" color="secondary">
      change behaviorSubject
    </ion-button>
  </ion-content>`,
})
export class HomePage implements OnInit {
  str: string;
  obj: { name: string };

  constructor(private data: DataService) { }

  ngOnInit() {
    this.data.strCurr.subscribe(data => this.str = data);
    this.data.objCurr.subscribe(data => this.obj = data);
  }

  chgLocal() {
    this.str = 'changed String';
    this.obj.name = 'changed Object';
    // --Output in HTML
    // parent data String: changed String
    // parent data Object: changed Object

    // child data String: default
    // child data Object: changed Object <--PROBLEM!

    // --Expected output in HTML
    // parent data String: changed String
    // parent data Object: changed Object

    // child data String: default
    // child data Object: Defaul
  }

  chgBehaviorSubject() {
    this.data.chgStr('behavior string');
    this.data.chgObj({ name: 'Behavior Object' });
  }
}

【问题讨论】:

    标签: angular typescript rxjs ionic4 behaviorsubject


    【解决方案1】:

    问题是由于对象的突变,而不是行为主体所独有的。对象是通过引用传递的,当你改变父对象中的对象时,它也会改变引用同一对象的其他地方。

    你可以的

    this.data.objCurr.subscribe(data => this.obj = {...data}); // Assuming there are no nested objects inside data
    

    在嵌套对象的情况下,您可以使用JSON.parse(JSON.stringify(data)),尽管它的性能不是很好,并且可以使用 lodash 之类的东西作为深度克隆实用程序(或者您也可以编写一个递归函数来克隆嵌套对象)

    【讨论】:

    • 我强烈建议使用JSON.parse(JSON.stringify(data))的替代品
    • @lealceldeiro 是的,我已经提到它不是高性能的,不应该是首选。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-12
    相关资源
    最近更新 更多