angular - BehaviorSubject 的行为与字符串和对象不同
问题描述
我试图在 ionic/angular 项目中使用数据服务来跨组件共享数据,但该服务没有像我预期的那样与对象一起工作。
在一个组件(即:父组件)中,当从订阅服务获取属性值的本地对象的值发生更改时,它会将值传播到其他组件,但我认为如果通过更改值可能会发生这种情况使用 next() 服务。
下面是一个空白离子项目中的最小示例,用于比较此场景中的字符串和对象。在父组件中有两种方法,一种更改本地值(发生问题的对象是对象而不是字符串),另一种通过服务更改值(按预期工作)。
我可能做错了什么,behaviourSubject 以这种方式与对象一起工作还是有问题?
数据服务.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);
}
}
主页.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' });
}
}
解决方案
问题是由于对象的突变而不是行为主体所独有的。对象是通过引用传递的,当您改变父对象中的对象时,它也会更改引用同一对象的其他位置。
你可以做
this.data.objCurr.subscribe(data => this.obj = {...data}); // Assuming there are no nested objects inside data
在嵌套对象的情况下,您可以使用它,JSON.parse(JSON.stringify(data))
尽管它的性能不是很好,并且可以将 lodash 之类的东西用于深度克隆实用程序(或者您也可以编写一个克隆嵌套对象的递归函数)
推荐阅读
- c++ - 在 C++ 中更优雅地打破循环引用
- angular - Angular - 使用辅助路由生成 routerLink
- machine-learning - 我应该先执行交叉验证,然后再进行网格搜索吗?
- html - HTML 更改图像大小
- sql-server - 将自动生成的 id 传递给其他表
- spring-boot - 添加 AWS 依赖项后的 War 文件上传问题
- android - Kivy Apk 与 firebase 管理员崩溃
- mysql - 如何从MYSQL中任意长度的字符串中删除特殊字符
- python - 'datetime.time' 对象在 django admin 中没有属性 'date'
- vue.js - 无法使用 vue-html2pdf 将 HTML 代码转换为 PDF