观察者——获取最上次的值

Observer - get the most last value

我需要发送一个包含大量数据的请求。这些数据来自 6 个不同的组件 - 所以基本上没有 reactive approach 很难做到。我决定做一些类似 ngrx component store 的实现(由于某些原因我决定自己实现它)。

我创建了一个作为组件提供者提供的商店实现,创建了一个保存在 BehaviorSubject 中的状态,创建了一个将状态映射到所需状态的简单 select 函数数据。在 ngOnInit Parent Component 中,我向后端服务器发出请求以获取 foos,并设置了一个 foo.isLoading 标志。然后我订阅并收听 foo.data 变化。如果是 - 我正在调用后端服务器 - 我正在设置 boo.isLoading 并且正在获取 boos.

FoosBoos 被正确获取但是 boo.isLoading 标志存在问题 - 我相信它来自调用状态观察者的顺序。步骤:

  1. foo.isLoading 设置为 true

  2. foo.data设置为后端响应,foo.isLoading设置为false

  3. 然后 foo observer 收到值并发出 HTTP 请求以获取 boos。

  4. boo.isLoading 设置为 true 并发送 HTTP 请求

  5. boo.isLoading 观察者收到 true

  6. 但是由于状态改变了两次 - boo.isLoading 观察者没有收到第一个值,而现在他们收到了,所以最后收到的值是 false

有什么解决办法吗?我已经尝试将 switchMap 状态更改为 of(state),因此当新值“到达”时应该取消之前的订阅,但它不起作用。

源代码在这里:https://stackblitz.com/edit/angular-ivy-qgbdxx

问题是您正在使用读取来触发此选择器中的写入。

this.parentStore.select(state => state.foo.data).pipe(
   filter(data => !!data),
   tap(_ => this.parentStore.loadBooData())
).subscribe();

并且由于 FooLoadCompletionBooLoadStart 进程是同步的,执行顺序打乱了您的流程。

我会尽力解释的。

FooLoadComplete 触发以下选择器的执行,因为它们是在订阅的那一刻。

onFooLoadComplete
   selector(foo.data).next(['a','b','c','d'])
   selector(foo.isLoading).next(false)
   selector(boo.isLoading).next(false)

但是由于您在 foo.data 选择器中触发了 BooLoadStart 副作用,执行顺序最终变成了这样。

onFooLoadComplete
  selector(foo.data).next(yourData)
    BooLoadStart
      selector(foo.isLoading).next(false)
      selector(boo.isLoading).next(true)
  selector(foo.isLoading).next(false)
  selector(boo.isLoading).next(false)

因此 boo.isLoading 值在选择器中以您期望的相反顺序进行处理。这就是选择器打印 false.

的原因

为避免此类问题,您应该保持 READ 和 WRITE 管道独立。

在您提供的代码中,您可以解决它删除 foo.data 选择器副作用并在 loadFooData

的 setTimeout 中调用 loadBooData
loadFooData() {
  this.state.next({
    ...this.state.value,
    foo: {
      ...this.state.value.foo,
      isLoading: true
    }
  });

  setTimeout(() => {
    this.state.next({
      ...this.state.value,
      foo: {
        ...this.state.value.foo,
        isLoading: false,
        data: ['a', 'b', 'c', 'd']
      }
    })

    this.loadBooData();

  }, 2000)
}

希望对你有所帮助

干杯