【问题标题】:new BehaviorSubject returning Null Id新的 BehaviorSubject 返回 Null Id
【发布时间】:2022-01-09 18:12:33
【问题描述】:

我正在创建购物车,但我遇到了这个奇怪的问题,购物篮的 ID 始终为空 篮子.ts

import { v4 as uuidv4 } from 'uuid';

export interface IBasket {
  id: string;
  items: IBasketItem[];
}

export interface IBasketItem {
  id: number;
  productName: string;
  price: number;
  quantity: number;
  pictureUrl: string;
  brand: string;
  type: string;
}

export class Basket implements IBasket {
  id: string = uuidv4();
  items: IBasketItem[] = [];
}

提篮服务

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { BehaviorSubject, map } from 'rxjs';
import { environment } from 'src/environments/environment';
import { Basket, IBasket, IBasketItem } from '../shared/Models/basket';
import { IProduct } from '../shared/Models/product';

@Injectable({
  providedIn: 'root',
})
export class BasketService {
  baseUrl = environment.apiUrl;

  private basketSource = new BehaviorSubject<IBasket>(null);
  basket$ = this.basketSource.asObservable();

  constructor(private http: HttpClient) {}

  getBasket(id: string) {
    return this.http.get<IBasket>(this.baseUrl + 'basket?id=' + id).pipe(
      map((basket: IBasket) => {
        this.basketSource.next(basket);
      })
    );
  }
  setBasket(basket: IBasket) {
    return this.http.post<IBasket>(this.baseUrl + 'basket', basket).subscribe(
      (response: IBasket) => this.basketSource.next(response),
      (error) => {
        console.log(error);
      }
    );
  }
  getCurrentBasketValue() {
    return this.basketSource.getValue();
  }

  addItemToBasket(item: IProduct, quantity = 1) {
    const itemToAdd: IBasketItem = this.mapProductItemToBasketItem(
      item,
      quantity
    );

    const basket = this.getCurrentBasketValue() ?? this.createBasket();

    basket.items = this.addOrUpdateItem(basket.items, itemToAdd, quantity);
    console.log(basket);
    // this.setBasket(basket);
  }
  private addOrUpdateItem(
    items: IBasketItem[],
    itemToAdd: IBasketItem,
    quantity: number
  ): IBasketItem[] {
    const index = items.findIndex((i) => i.id === itemToAdd.id);
    if (index === -1) {
      itemToAdd.quantity = quantity;
      items.push(itemToAdd);
    } else {
      items[index].quantity += quantity;
    }
    return items;
  }
  private createBasket(): IBasket {
    const basket = new Basket();
    console.log('ezeze');
    localStorage.setItem('basket_id', basket.id);
    return basket;
  }
  private mapProductItemToBasketItem(
    item: IProduct,
    quantity: number
  ): IBasketItem {
    return {
      id: item.id,
      productName: item.name,
      price: item.price,
      pictureUrl: item.pictureUrl,
      quantity,
      brand: item.productBrand,
      type: item.productType,
    };
  }
}

product-item.ts

import { Component, OnInit, Input } from '@angular/core';
import { BasketService } from 'src/app/basket/basket.service';
import { IProduct } from 'src/app/shared/Models/product';

@Component({
  selector: 'app-product-item',
  templateUrl: './product-item.component.html',
  styleUrls: ['./product-item.component.scss'],
})
export class ProductItemComponent implements OnInit {
  @Input() product: IProduct;

  constructor(private basketService: BasketService) {}

  ngOnInit(): void {}

  addItemToBasket() {
    this.basketService.addItemToBasket(this.product);
  }
}

产品项目.html

<div class="card h-100 shadow-sm">
  <div class="image position-relative" style="cursor: pointer">
    <img
      src="{{ product.pictureUrl }}"
      alt="{{ product.name }}"
      srcset=""
      class="img-fluid bg-light"
    />
    <div class="d-flex align-items-center justify-content-center hover-overlay">
      <button
        (click)="addItemToBasket()"
        type="button"
        class="btn btn-secondary fa fa-shopping-cart me-2"
      ></button>

      <button
        routerLink="/shop/{{ product.id }}"
        type="button"
        class="btn btn-secondary"
      >
        view
      </button>
    </div>
  </div>

  <div class="card-body d-flex flex-column">
    <a routerLink="/shop/{{ product.id }}">
      <h6 class="text-uppercase">{{ product.name }}</h6>
    </a>
    <span class="mb-2">{{ product.price | currency }}</span>
  </div>
</div>

所以当我点击购物篮的 id 始终为空的产品时,基本上会出现问题 项目正在加起来,但 Id 为空

例如:{ "id": "null", “项目”: [ { “身份证”:8788, "productName": "T Blues", “价格”:20, "pictureUrl": "*********/images/products/bo.png", “数量”:1, “白兰地”, “类型”:“Z” } ] }

知道如何解决这个问题吗?

【问题讨论】:

  • 您是否从 API 调用中获取篮子?如果是这样,该 API 调用的响应是否具有购物篮 ID 的值?
  • 您需要告诉我们您是否在组件中获得了id。另外,像你这样看它为 null ,否则无法正确调试
  • 我正在使用 uuid 生成 Id,事情是 private basketSource = new BehaviorSubject&lt;IBasket&gt;(null);this.basketSource.getValue() 总是在 console.log 中返回 null 像这样 { "id": "null", "items": [] }

标签: javascript reactjs angular ecmascript-6 rxjs


【解决方案1】:

BehaviorSubject 返回发送给它的最后一项。

您正在使用null 对其进行初始化:

(...)
  export class BasketService {
  baseUrl = environment.apiUrl;
//                                                     \/  here     
  private basketSource = new BehaviorSubject<IBasket>(null);

所以当你第一次订阅它的值时,它将产生null

我没有在您的组件上看到对 getBasket 的调用,它可能没有被调用...或者服务可能没有及时响应以将下一个值提供给 basketSource

BehaviorSubject's 也更适合用作 Observable,以避免其值出现问题。

您应该删除该功能

getCurrentBasketValue() {
    return this.basketSource.getValue();
  }

将 prop basketSource 设为 public,并在需要时将其值过滤掉空值,如下所示:

basketService.basketSource.pipe(filter(x=>x), take(1)).subscribe(source => {
  // your code here, 

})

【讨论】:

  • 但通常它应该从 Basket 类中获取初始值,初始值为 export class Basket implements IBasket { id: string = uuidv4(); items: IBasketItem[] = []; } 这是令人困惑的部分
猜你喜欢
  • 2020-02-25
  • 2019-06-16
  • 1970-01-01
  • 1970-01-01
  • 2014-12-26
  • 2019-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多