NgRx:倾听服务中的状态变化,而不是使用效果



我的问题是:服务是否可以监听状态更改并根据状态值进行http调用,还是必须由效果(NgRx)触发?因此,与其让一个服务被一个效果调用,就像你通常在网上看到的例子一样,你应该让一个服务器监听商店的一部分,并根据它做出反应。因此没有更多的效果。我的问题更像是一个哲学(最佳实践)问题,而不是一个技术问题,因为从技术上讲,两者都有效。

更新

下面是一个具体的案例来理解我为什么要问:

上下文:

我有一个从后台收到的元素列表。我可以过滤元素列表。一次可以有多个筛选器。过滤是在后端完成的。

当前实施:

组件分派一个FILTER_ELEMENTS操作。该操作被调用http服务的效果所接受。该服务向后端请求基于过滤器的元素列表。因为可能有多个过滤器,所以效果(或服务)需要知道当前的过滤器是什么,并将新的过滤器添加到该列表中。所以我在效果中添加了一个.withLatestFrom(this.state$),并从中获取当前的过滤器列表。

问题:

问题是没有使用新的筛选器更新状态。我可以在reducer中捕获FILTER_ELEMENTS操作并更新状态,但这会导致其他几个潜在问题。效果和减速器中的哪一个将首先被称为?如果出现后端错误怎么办?我的状态会用新的过滤器更新,但列表不会被过滤。异步主义呢?如果我在服务器回答之前或在状态更新之前要求另一个过滤器,该怎么办?

这对我来说有点太乱了。

所以我的问题是:商店到底是什么才是真理的源泉?相反,这不仅仅是一个"日志",记录发生的事情,可能是最新的,也可能不是最新的。我的意思是,想要添加过滤器的组件可以通过调度ADD_FILTER操作来完成,该操作将更新该状态中的过滤器列表。我的服务可以监听过滤器列表,并在每次列表更改时调用后端。因此,该服务只在状态发生变化时调用后端,并且我们所知道的是最新的真实状态。然后向带有更新列表的商店发送一个"成功"操作。我不认为这会导致比效应更多的潜在无限循环。。。毕竟,这些影响也会导致无限循环。。。因此,我的服务实际上是一种监听存储更改的效果,而不是直接监听操作。

您不应该这样做,因为它明确违反了单向数据流。异步事件导致操作进行更新存储,来自存储的数据不会触发新的异步事件,而这些事件又可能触发新的操作。这会产生严重错误的可能性,比如无限事件循环,也会使您的应用程序难以推理。特效服务的存在是出于这个原因,以确保单向数据流永远不会被违反。

重要的是要记住,使用ngrx,一个操作表示整个应用程序状态的更改,即完全停止。effects服务本质上采取了一个需要一些远程资源来描述完整状态更改的操作,并获取该远程资源并将其映射到一个新的操作中,该操作在完整状态更改进入存储之前表示完整状态更改。如果你正在根据商店里的东西进行进一步的状态更改,那么很明显,你没有在行动中充分描述你的状态更改。

实际进入商店的操作的回放每次都应该产生相同的状态,同样,如果你根据从商店得到的内容进行其他状态更改,情况就不会如此。

编辑以解决其他问题:

商店是设计的真理的单一来源,IE,应用程序的状态在没有经过商店的情况下不会更新。作为开发人员,你有责任强制执行这一点。它不应该是你追溯性地更新它以反映"发生了什么",它应该是实际的更改,存储区正在存储你的应用程序的状态。

就目前情况来看,您似乎想要过滤元素,然后通过调度UPDATE_FILTERS操作来对接收这些元素做出反应,这是100%错误的做法。

解决问题的第一步是确保您的操作包含状态更改所需的所有信息,因此,如果您的特效服务需要访问当前状态,则说明您做错了什么。FILTER_ELEMENTS操作应包含所有需要的过滤器,效果服务不应访问当前状态。

下一步是再次确保您的操作包含状态更改所需的所有信息。不要在减速器中捕捉FITLER_ELEMENTS,映射到一个新的动作ELEMENTS_FITLERED,该动作包含已过滤的元素和过滤器,并对此做出反应,并在同一动作中应用两个状态更改。在出现错误的情况下,您可以捕获它,并使用创建该状态所需的数据映射到FILTER_error操作中,该操作可能包括旧的过滤器。至于在完成旧的过滤器之前通过的新过滤器,则可以使用switchMap来确保查看最新的过滤器,并忽略以前的请求。

所有这些都可以在框架中解决,您的特效服务不应该导致无限循环,如果可以的话,您可能是因为试图访问特效服务中的状态而设计错误的。但你永远不应该用新的行动来回应行动。

最新更新