如何让 Observable 返回一组转换后的项目(Rxjs)

IT技术 angular reactjs rxjs observable
2021-04-26 04:35:51

我有一个生成 json 产品列表的端点。我在我的产品代码中定义了一个自定义类类型。我正在尝试从端点获取数据,并将产品的 json 数组转换为 Product 类的数组。

示例 API json(从我的实际数据中简化):

{
    "products": [{
        "id": 1,
        "name": "Product 1",
        "materials": [{
            "id": 100,
            "desc": "wood"
        }, {
            "id": 101,
            "desc": "metal"
        }]
    }, {
        "id": 2,
        "name": "Product 2",
        "materials": [{
            "id": 100,
            "desc": "wood"
        }, {
            "id": 102,
            "desc": "brick"
        }]
    }]
}

我的代码:

loadProducts(){
    this.fetchProducts().subscribe(data => {
            console.log("the data:", data);
        })
}


fetchProducts(): Observable<Product[]> {
    return this.http.get("http://example.com/mydata.json")
        .map((response) => {
            const products = (response.json()).products;
            console.log("Converting to json" + products.length);
            return products;
        })
        .map( data => {
            console.log("Working on data: ", data);
            return new Product(data.id, data.name, data.materials);
        });

我希望在我的控制台中看到的是..

"Converting to json 2"
"Working on data: " [object]
"Working on data: " [object]
"the data:" [object,object]

.. 但我所看到的是..

"Converting to json 2"
"Working on data: " [object,object]
"the data:" [object,object]

我认为 .map 函数会为发送给它的每个项目运行。我可以看到,当我第一次调用 .map 时,它正在它拥有的一个项目(响应)上运行一次 - 我知道有产品 2 个项目被返回。我希望第二个地图功能然后运行两次 - 每个产品项目一次。相反,它似乎一旦在产品数组中传递就被调用。

为了让事情变得更复杂,我还想将材料列表转换为我创建的 Material 类类型。我知道我可以用 forEach 循环来完成所有这些,但我想用“React”的方式来做到这一点。

2个回答

我终于找到了正确的 Observable 操作组合来产生我想要的。

fetchProducts(): Observable<Product[]> {
    return this.http.get("http://examples.com/myData")
        .map((response) => {
            return response.json().products;
        })
        .switchMap( productArray => {
            return Observable.from(productArray);
        })
        .map( (productData: any) => {
            return new Product(
                productData.id,
                productData.name,
                productData.materials
            );
        })
        .toArray();
}

我误解了 Observable.map 是如何工作的——认为它会在我的数据中的每个项目上运行,而实际上它在每条数据上运行......而且我收到了一条数据——一个数组。感谢@jonrsharpe 在那里帮助我。

通过使用 switchMap 从我的数组中返回一个新的 Observable,我能够分别发出数组中的每条数据。感谢@giora-guttsait 的帮助。

最后,我需要将流的所有这些新部分组合回单个数组。Observable.toArray() 为我做了这个。

在你的情况下,你会得到这样的东西:

this.http.get(...)
  .map(res => res.json().products)  // turns this into Observable<Products[]>
  .map(products => ... ) // here, products is already an array.

如果你想像在 React 中一样处理这个数组,意味着为每个产品做一些事情,你可以这样做:

this.http.get(...)
  .map(res => res.json().products)
  .switchMap(products => Observable.from(products))

在这里,Observable.from(products)返回Observable<Product>switchMap使链回报Observable<Product>你以前有。

this.http.get(...)
  .map(res => res.json().products)
  .switchMap(products => Observable.from(products))
  .subscribe(product => console.log(product))

将打印这些产品中的每一种。

免责声明:我没有通过运行它来检查此代码,那么您可能需要不同的运算符switchMap,但我记得这是有效的