【问题标题】:How do I subscribe to and update individual properties deeply nested inside a BehaviorSubject?如何订阅和更新深层嵌套在 BehaviorSubject 中的单个属性?
【发布时间】:2019-11-23 08:55:19
【问题描述】:

我需要创建一种方法来动态构建可单独订阅的 observable 数据存储。我使用BehaviorSubject 是因为生成的数据的值可能会发生变化,需要反映。

我正在创建一个模块,用于从如下面的界面形状的数据对象生成SVG 代码。

export interface GraphicElement{
    element: string;
    elementId: string;
    selfClosing?: boolean;
    bind?: GraphicBinding; //this property is most relevant to this question
    value?: string;
    properties: GraphicProperties;
    responsiveProperties?: ResponsiveProperties;
}

export interface GraphicBinding{
    library: string;
    property: string;
}

在我的模块中,我有一个封装所有代码的svg-shell-component,一个将GraphicElement 对象迭代到svg-element-componentsvg-element-component,它生成svg 元素并将其注入到模板中。

可选的bind 属性将让组件知道需要将值绑定到该元素。为了给出一个真实世界的例子来更好地说明我在做什么,我有一个product-spec-component,它显示了产品的图表,其中包含不同尺寸、零件尺寸、开/闭跨度等的测量值,具体取决于产品。 product-data 是与graphic-data 分开的存储区,它包含不同维度的所有测量值,这些测量值将用于生成应在显示测量值的svg-element-component 实例中绑定到的数据。用户还可以在英寸和厘米之间切换,这将更新本示例中绑定的属性的值。

我处理这种情况的方法是使用服务文件来动态生成和设置这些属性,如下面的界面形式。

export interface GraphicBindingData{ [library: string] : GraphicBindingProperty; }
export interface GraphicBindingProperty{ [property:string] : string; }

所以在这个例子中会在服务文件中生成一个类似这样的对象

BindingData: GraphicBindingData = {
     specMeasurements:{
        width: '2in',
        height: '5in',
        thickness: '.125in',
        depth: '9in'
    },
    someOtherLibrary:{
        somePropA: 'some value',
        somePropB: 'some value'
    }
}

回到GraphicBinding 接口的GraphicElement 接口中的bind 属性,library 属性将设置为specMeasurementsproperty 属性将设置为任何一个的名称它需要绑定到的维度。

因此,我们称之为binding-data-service 文件将被导入product-spec-component 以设置此数据,而graphic-element-component 将使用bind 属性中的值来订阅它需要的任何属性.我添加了另一个虚拟数据对象,因为我想展示如何可能存在其他属性对象,以进一步强调是什么让我难以弄清楚如何将BehaviorSubject 应用于这种情况因此,单个库或可能仅在一个库中的单个属性可能会发生变化,而其他一切都保持不变。在这个带有product-spec-component 的示例中,这不是什么大问题,但在如何使用该模块的其他方面,可能会有更多对象具有更深层次的数据。

我正在考虑执行以下操作。

export interface GraphicBindingData{ [library:string] : BehaviorSubject<GraphicBindingProperty>; }
export interface GraphicBindingProperty{ [property:string] : BehaviorSubject<string>; }

在考虑了BehaviorSubject 通常如何被另一个变量观察到然后订阅之后,我不确定如何为每个库中的每个属性创建一个观察者。我也不确定在这种情况下必须如何使用.next() 来更新数据。我一直在尝试查找有关在 BehaviorSubjects 中使用 BehaviorSubjects 的更多信息,如果这对于我想要实现的目标来说是必要的,但找不到任何东西。有人可以帮助我了解如何塑造它,以便我可以订阅和更新各个属性而不影响其他可观察对象吗?

【问题讨论】:

    标签: angular typescript rxjs


    【解决方案1】:

    我不推荐嵌套行为主题,它会让你的流消费更加复杂,使用单个状态对象并应用一些过滤逻辑可能会更好

    假设你有一个像

    这样的对象
    const myObj=new BehaviorSubject({orange:{apple:{cherry:'my cherry'},banana:'my banana'})
    

    并且你想更新cherry(在这里重建不可变对象可能会很痛苦)

    myObj.next({orange:{apple:{cherry:'my cherry updated'},banana:'my banana'})
    

    并注意樱桃变化

    myObj.pipe(pluck('orange','apple','cherry'), distinctUntilChanged())
    

    因为每当其中一个值发生更改时,您都必须 .next() 整个对象,所以要做到这一点,您必须破坏并重新构造状态对象

    const obj=myObj.value
    //add a grape
    myObj.next({...obj ,orange:{...obj.orange, grape:'my grape'}})
    
    // or json stringify then json parse
    const obj=JSON.parse(JSON.stringify(myObj.value))
    obj.orange.grape='my grape'
    myObj.next(obj)
    

    或者,如果您不想要不变性,您可以直接设置属性

    let obj=myObj.value
    obj.orange.grape='my grape'
    myObj.next(obj)
    

    【讨论】:

    • 平滑解决方案
    • 嗯。好的,如果我有类似orange:{apple:{cherry: 'my cherry', grape: 'my grape'}} 的东西怎么办?我可以在不影响葡萄的情况下更换樱桃吗?我认为.next() 在这种情况下会消除葡萄。但随后我可以将整个对象存储在函数内部的一个变量中,并在那里重写樱桃并用相同的葡萄值重置它。
    • 是的,正如您所说,您可以将整个对象存储在一个没有可观察的变量中,但是您只是失去了反应性,您无法将值更改作为事件知道。 next() 是为了让其他函数显式地改变值来订阅()
    【解决方案2】:

    国家管理呢

    你必须使用 NgRx 来为这个 porperties 树的所有状态更改使用

    【讨论】:

      【解决方案3】:

      好的,我最终找到了实现这一目标的方法。我不得不像这样重新塑造我的界面

      export interface BindingObject{ [library:string] : BindingItem; }
      export interface BindingItem{ [property:string] : BehaviorSubject<string>; }
      
      export interface BindingObjectObservable{ [library:string] : BindingItemObservable; }
      export interface BindingItemObservable{ [property:string] : Observable<string>; }
      

      因此,我没有将一个实体对象作为BehaviorSubject,将另一个作为Observable,而是将每个属性都设置为BehaviorSubject,然后单独观察和订阅它,并且可以在不影响库中的其他属性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-11-30
        • 2019-01-13
        • 1970-01-01
        • 2020-02-13
        • 2016-07-12
        • 1970-01-01
        • 1970-01-01
        • 2011-07-08
        相关资源
        最近更新 更多