Rxjs Behavior Subject 值更改而不调用 next

Rxjs Behavior Subject value changes without calling next

假设我的服务中有一个行为主体:

theRuleSbj = new BehaviorSubject<Rule>(null);

然后在我的组件中使用 getValue() 方法获取该值:

this.rule = this.ruleService.theRuleSbj.getValue();

然后如果我更改本地规则对象中的一些数据。例如:

this.rule.name = 'name';

我的行为主体值也变了,没调用next!似乎我的变量绑定到行为主体,所以我的局部变量的每一个变化都会影响我的行为主体。 这是主体行为行为吗!!??或者我做错了什么? (假设我在更改局部变量时不想更改行为主体)。

更新:

我测试了标记答案中的解决方案,它适用于一个简单的对象。但实际上在我的情况下,如果你有一个嵌套对象(对象内的对象),这是行不通的,我发现 this link 中的 "deep copy" 术语非常适合我。

这是因为 BehaviorSubject returns 你 link 它的当前值。当你做类似

的事情时
this.rule.name = 'name';

object 属性 值改变了,但是 link shared for everyone 还是一样的。 如果您需要在本地更改规则值,请尝试

this.rule = {...this.rule, {name: name}}

它会在不更改源值的情况下覆盖您的本地 link

对象属性在 Javascript 中通过引用传递。有关详细信息,请参阅 here。也就是说,使用 getValue() 访问可观察对象并不是那么优雅。您可以在不修改源的情况下订阅获取值。

服务

theRuleSbj = new BehaviorSubject<Rule>(null);
ruleObs = this.theRuleSbj.asObservable();

组件

this.ruleService.ruleObs.subscribe(rule => { this.rule = rule });

要将您的值从 Subject 中推出,请从中创建一个 Observablesubscribe

如果你想要值的本地版本,由于在 JavaScript 中通过引用传递对象,你需要复制一份,所以在订阅时创建一个新对象。

您可以使用 Spread Syntax 来做到这一点。

然后你可以在不影响 Subject.

的情况下为本地对象分配任何你喜欢的值

例如(StackBlitz)

    const theRuleSbj = new BehaviorSubject<Rule>(null);
    const theRule$ = theRuleSbj.asObservable(); 
    
    // The observable will emit null on the initial subscription
    // Subject might be a better fit
    theRule$.subscribe(rule => {
        console.log(`Subscription value:`, rule);
        // Use object spread to create a new object for your component
        this.rule = { ...rule };
      });
    
    // Update the Subject, it will console log new value
    // and update your local value
    theRuleSbj.next({ name: 'Name 1'});
    
    // Update your local value, does not effect your Subject value
    this.rule.name = 'Name 2'; 
    
    // Confirm that they are differant
    console.log(`Subject Value:`, theRuleSbj.getValue());
    console.log(`Local Value`, this.rule);
    
    // Be careful as when you update the Subject, your local value will be updated
    theRuleSbj.next({ name: 'Name 3'});
    console.log(`Subject Value (after subject update):`, theRuleSbj.getValue());
    console.log(`Local Value (after subject update)`, this.rule);

请注意,订阅后您会将主题值的所有更新推送到您的本地值,您可能希望也可能不希望发生这种情况。

如果你只想要组件中的一个值,你可以 pipe() observable 并使用 take(1) 得到一个值,但是当你初始化 SubjectBehaviourSubject,你只会得到 null 的值。您可能希望将其更改为 Subject,因此当第一个值被推送到 Subject 时,您的组件会收到它。


    const theRuleSbj = new Subject<Rule>();

    /* other code omitted  */

    theRule$
        .pipe(take(1))
        .subscribe(rule => {
            console.log(`Subscription value:`, rule);
            this.rule = { ...rule };
        });