Angular 中的状态管理

由于之前一直用的是 Vue 和 React,对 Angular 还不是很熟悉,对于 Vue 或者 React 来说,每一个单独的组件都有它自身的状态,例如 Vue:

export defaut {
    data() {
        return {
            message: "hello world",
        }
    }
}

它这个状态是响应式的,通过更改 message 的值,能够实时更新页面上对应的组件。

而 Angular 的组件自身是没有状态,需要额外构建一个 service ,通过依赖注入的方式将状态注入到组件中,例如构建一个 ProductService :

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class ProductService {

  private cart = [];

  constructor() { }

  add(product) {
    this.cart.push(product);
  }

  items() {
    return this.cart;
  }

  clear() {
    this.cart = [];
  }

  pop() {
    this.cart.pop();
  }

  delete(index) {
    this.cart.splice(index, 1);
  }
}

将 service 注入到组件中:

import { Component, OnInit } from '@angular/core';
import {ProductService} from '../product.service';
import ProductEntity from '../product/product.entity';

@Component({
  selector: 'app-cart',
  templateUrl: './cart.component.html',
  styleUrls: ['./cart.component.scss']
})
export class CartComponent implements OnInit {

  products = [];

  constructor(
    private productService: ProductService
  ) {
    this.products = this.productService.items();
  }

  ngOnInit() {

  }

  addProduct() {
    console.log('add a product');
    const product = new ProductEntity();
    product.title = 'title';
    product.vendor = 'vendor';
    product.amount = 2;
    product.price = 10.34;
    product.image = 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1574427664957&di=edc50707e20a3268e5a9cc9d4d3af942&imgtype=0&src=http%3A%2F%2Fauctions.c.yimg.jp%2Fimages.auctions.yahoo.co.jp%2Fimage%2Fdr225%2Fauc0211%2Fusers%2F0%2F6%2F1%2F6%2Fkfd02165-img600x456-1367615877ojjb6n79301.jpg';

    this.productService.add(product);
  }
  rmProduct() {
    console.log('remove a product');
    this.productService.pop();
  }
  get total() {
    let totalPrice = 0;
    this.products.forEach(product => {
      totalPrice += product.amount * product.price;
    });
    return totalPrice;
  }
}

这种方式既有好处也有坏处,首先 Angular 这种方式写起来比较繁琐,因为每个组件都要添加对应的 service (这里针对有状态组件而言),因此 Angular 不适合构建大量粒度比较细的组件,而 Vue 和 React 在这方面是强项,不过这种方式也有好处,就是状态与组件分离了,那么组件之间的消息传递就会变得十分简单,不像 Vue, 它如果需要在完全不相关的组件之间传递数据,需要引入消息总线(event bus)或者 Vuex,因为它们的组件之间的状态是独立的,而 Angular 只需要将对应的 service 通过依赖注入注入到不同组件即可。

一些注意项:

  • 获取组件数组索引
 <div class="" *ngFor="let product of products; index as i">
    <app-product [product]="product" [index]="i"></app-product>
  </div>
  • 获取特定组件的 event ,例如 input 框:
    <div class="amount">
          <input type="number" value="{{product.amount}}" (change)="changeAmount(index, $event)">
    </div>

这里没有使用双向绑定是因为需要同步更新 service 中的状态。

以上代码的另外一种推荐写法:

 <div class="amount">
          <input type="number" value="{{product.amount}}" #amount (change)="changeAmount(index, amount.value)">
 </div>

应该尽可能使用第二种写法。