【问题标题】:Subject emits previous value主题发出先前的值
【发布时间】:2021-01-31 10:48:50
【问题描述】:

我在我的应用程序中使用 Subject 来进行 CRUD 操作。我在几个组件中订阅了它,但它似乎并没有实时改变我的价值观。我不得不求助于重新加载页面来获取最新的值。这可能是由于我对如何组织所有内容缺乏了解,但我在这里没有发现任何类似的问题。你能帮我解决我做错了什么吗? (使用 BehaviourSubject 产生相同的结果)。 这是我的服务的代码:

    @Injectable({ providedIn: 'root' })
export class AppBookshelfService {
  filesAndFolders: ItemFile[] = [];
  filteredArrOfFolders = [];
  filesSubj = new Subject();
  curentParent = 0;
 
  getFiles() {
     this.http.get<any>('http://localhost:3000/api/items').subscribe(
       (data: any) => {
         this.filesAndFolders = data.items;
        this.filesAndFolders = data.items.filter(item => item.isDeleted === 0);  
        this.filesSubj.next(data.items.filter(item => item.isDeleted === 0)); 
         data.items.forEach(item => {
           if(item.parentId !== 0 && item.isFolder === 1) {
            this.filteredArrOfFolders.push(item);
           }
         });     }
     )
  }

  getFile(id: number): Observable<ItemFile> {
    return this.http.get<ItemFile>("http://localhost:3000/api/items/" + id);
  }

  emitIdForFile(parentId: number) {
    this.curentParent = parentId;
  }

  getCurentParent() {
    return this.curentParent;
  }

  postFile(item: ItemFile) {
    return this.http.post<ItemFile>("http://localhost:3000/api/items/", item).subscribe(result => {})
  }

这是我的一个关键组件的代码,用于订阅:

 ngOnInit(): void {
    this.bookshelfService.getFiles();
    this.sub = this.bookshelfService.filesSubj.subscribe(data => {
      this.files = data;
      console.log(this.files)
      let groupOfCheckboxes = {};
      this.files.forEach(element => {
        groupOfCheckboxes[element.id.toString()] = new FormControl("");
      });
      this.checkboxForm = new FormGroup(groupOfCheckboxes);
    });

    // this.getFolders();

  }

  ngOnDestroy(): void {
    this.sub.unsubscribe();
  }

  startCreatingFolder() {
    this.isFolderBeingCreated = !this.isFolderBeingCreated;
  }

  createFile(id: number) {
    this.bookshelfService.emitIdForFile(id);
    this.router.navigate(['create']);
  }

  createFolder(event, id) {
    const folder = {
      name: this.folderNameInput.nativeElement.value,
      description: "",
      imageLink: "",
      isDeleted: 0,
      parentId: id,
      isFolder: 1
    }
    this.bookshelfService.filesAndFolders.push(folder);
    this.bookshelfService.getFiles();
    this.bookshelfService.postFile(folder);
    this.isFolderBeingCreated = false;
  }

这里是完整存储库的链接: https://github.com/Not-a-whale/BookshelfApp

这是在 Heroku 上运行的应用程序,存在上述缺陷: https://bookshelf-app-nikita.herokuapp.com/

【问题讨论】:

    标签: javascript angular typescript rxjs subject


    【解决方案1】:

    主题是 Hot(Multicast),您应该在发出之前订阅它:

     ngOnInit(): void {
        
        this.sub = this.bookshelfService.filesSubj.subscribe(data => {
          this.files = data;
          console.log(this.files)
          let groupOfCheckboxes = {};
          this.files.forEach(element => {
            groupOfCheckboxes[element.id.toString()] = new FormControl("");
          });
          this.checkboxForm = new FormGroup(groupOfCheckboxes);
        });
    
         this.bookshelfService.getFiles();
         // this line must be after subscribe
    
        // this.getFolders();
    
      }
    

    当数据在 Observable 内部产生时,Observable 是冷的,而当数据在 Observable 外部产生时,Observable 是热的。正如我们刚刚看到的,热门的 Observable 能够在多个订阅者之间共享数据。我们称这种行为为“多播”。 生成随机数不是一个好的现实用例。一个好的用例是 DOM 事件。假设我们正在跟踪点击行为并让多个订阅者对坐标进行操作:

    数据是在 Observable 本身之外产生的。这使它变得很热,因为无论是否有订阅者,都会创建数据。如果在生产数据时没有订阅者,数据就会丢失。

    More Info

    如果你想将 data_list 保存在内存中,然后多次使用它,请使用 behaviorsubject 来保存它,主题没有内存来保存事件。

    behaviorsubject 需要一个默认值,因此您必须使用一个空列表对其进行初始化。

    当您使用新数据调用行为主体旁边的服务时,然后在服务调用之前订阅它以接收更改事件

    // RxJS v6+
    import { BehaviorSubject } from 'rxjs';
    ​
    const subject = new BehaviorSubject(123);
    ​
    // two new subscribers will get initial value => output: 123, 123
    subject.subscribe(console.log);
    subject.subscribe(console.log);
    ​
    // two subscribers will get new value => output: 456, 456
    subject.next(456);
    ​
    // new subscriber will get latest value (456) => output: 456
    subject.subscribe(console.log);
    ​
    // all three subscribers will get new value => output: 789, 789, 789
    subject.next(789);
    ​
    // output: 123, 123, 456, 456, 456, 789, 789, 789
    

    【讨论】:

    • 我按照您的说明进行了更改,但完全没有帮助
    • 只订阅getFiles()方法获取数据,为什么要用subject?
    • 您是否尝试过使用 ReplaySubject 或 AsyncSubject 代替您的主题?
    猜你喜欢
    • 1970-01-01
    • 2020-11-13
    • 2016-02-14
    • 1970-01-01
    • 2017-05-26
    • 2021-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多