ngrx无状态组件+与商店交互

时间:2020-09-25 17:06:31

标签: angular redux ngrx

是否可以编写与ngrxs存储交互的无状态组件?

我见过的几乎所有示例都没有使用@Input向组件提供状态,而是使用了组件内部的this上下文来通过选择器检索状态,这从定义上使组件具有状态。

我不相信ngrx中有任何等效的mapStateToProps,这将允许与商店进行无状态交互。

1 个答案:

答案 0 :(得分:1)

我给你举个例子。

假设您在应用程序中有一个方面负责显示待售产品。

products.component.ts(有状态组件)

product$ = this.store.select(getProducts);
selectedProduct: IProduct;
constructor(private store: Store<ProductsState>) { }

setSelectedProduct(product: IProduct) {
  this.selectedProduct = product;
}

products.component.html

<product-details *ngFor="let product of products$ | async"
   [product]="product"
   (productSelected)="setSelectedProduct($event)"
></product-details>
<div class="selected-product" *ngIf="selectedProduct">
  <selected-product
    [product]="selectedProduct"
  ></selected-product>
</div>

product-details.component.ts(无状态,负责侦听产品点击并发出被点击的商品)

@Input() product: IProduct;
@Output() productSelected = new EventEmitter<IProduct>();

onProductSelect() {
  this.productSelected.emit(this.product);
}

product-details.component.html

<div (click)="onProductSelect()">
  <div>{{ product.id }}</div>
  <div>{{ product.name }}</div>
</div>

selected-product.component.ts(负责在底部显示被点击的产品)

@Input() product: IProduct;

selected-product.component.html

<img src="product.img" alt="product image" />
<div class="rating">{{product.rating}}</div>
<div *ngFor="let comment of product.reviewComments"> {{ comment }}</div>

因此,想法是制作一个与您的应用程序相关的功能片,一个组件将是有状态的组件(知道如何与商店交谈),即products.component.ts。其他每个视图都会获得输入的数据。

这不能解决支柱钻探的问题,但是可以轻松地对具有@Input()和@Output()的组件(无状态组件)进行单元测试。

我在React中也使用了这种方法,因为我有一个有状态的组件(带有mapDispatchToProps和mapStateToProps),然后将这些属性作为道具传递给了下手,使得单元测试更加容易。

我也不认为React中的mapStateToProps子组件是无状态的,因为它们仍然必须知道如何从商店读取数据,并且为此编写单元测试也很困难,因为您必须模拟存储或在进行单元测试时提供存储。

这种道具钻探的另一个优点是,一个组件负责从存储中读取数据,如果存储的结构发生变化,则必须在一个组件中进行代码更改,并且属性将像以前一样下降。但是,如果采用每个具有mapStateToProps的子组件的方法,则将在每个具有mapStateToProps的地方进行商店结构的更改。

如果您想在多个地方使用this.store.select(),也可以,但是在多个地方都相当于mapStateToProps。基本上,如果您可以按照概述进行钻探,那么单元测试和重构将更加容易。