ngrx声明(here for example)的支持者,您可以并且应该将所有应用程序状态保存在单个商店中。这表明@ ngrx / Store可以用于缓存,因为缓存的内容是一种应用程序状态。
Web应用程序中的缓存是一种在它拥有数据时返回数据的东西,并且当它没有时封装从服务器请求数据。 Wikipedia article on caching在数据可用时将其称为缓存命中,而在数据不可用时将其称为缓存未命中。
从功能编程的角度来看,我们可以立即看到从缓存中读取数据在功能上是不纯的 - 它有副作用,即可以从服务器请求数据并保留在缓存中。我不知道如何用ngrx做到这一点,例如,要求其选择器在功能上是纯粹的。
考虑这个Caching With RxJs Observables in Angular教程可能有所帮助(据说rxjs与ngrx极为互补)。我们没有必要向远处滚动才能找到带有副作用的getFriends()
函数:
getFriends() {
if(!this._friends){
this._friends = this._http.get('./components/rxjs-caching/friends.json')
.map((res:Response) => res.json().friends)
.publishReplay(1)
.refCount();
}
return this._friends;
}
此外,Store的内容似乎普遍适用于整个应用程序。唯一的控制是关于如何更新状态,但是在缓存的未处理的原始数据中徘徊是愚蠢的,因为无法保证哪些缓存项可用且哪些不可用。
希望这些担忧能够得到缓解,并且我已经错过了这样做的方法。请问您能否将@ ngrx / Store用作缓存?
答案 0 :(得分:1)
在ngrx中有减速器(纯函数)可以改变状态(或缓存)。这些减速器由您在商店发送的动作触发。
从商店中,您可以通过选择器请求数据切片并订阅他们的更改。
要实现缓存逻辑,请检查数据是否可用,如果不可用 发送一个像“LoadDataSliceAction”这样的动作,它会触发一个副作用然后将数据加载到商店中。
这有帮助吗?
答案 1 :(得分:0)
我发现了两种主要方法。它们都涉及为商店的任何需要过期的部分添加时间戳。第一种是检查选择器功能中的年龄,如果超过了限制,则只需分派检索操作。使用createSelector语法并可以访问商店进行分发,这一点相当简单。另一个要求您按正常方式调度检索操作,然后在检索之前检查效果中的数据寿命。这可以通过将可观察到的sttore与combinLatest(https://medium.com/@viestursv/how-to-get-store-state-in-ngrx-effect-fab9e9c8f087)之类的东西组合来实现。
第一个选项示例
createSelector(previousSelector, (item) => {
const now = new Date();
const limit = new Date(now.getTime() - (5 * 60000));
if (item.age < limit) {
this.store.dispatch(new getFreshDataAction());
}
});
答案 2 :(得分:0)
值得注意的是,浏览器标配缓存,这是真正的交易,封装请求和封装数据,因为它不具有问题中讨论的nrgx的局限性。
这些天,我们正在使用浏览器缓存来存储实体。从here借用我的定义:
实体是一个具有长期数据值的对象,您可以从服务器读取该数据(并有可能写回该数据)。
实体数据只是一种应用程序数据。配置数据,用户角色,用户的先前选择,屏幕布局的当前状态…这些都是重要的数据,可以从使用标准ngrx技术进行编码中受益,但它们不是实体。
这会篡改Redux的基本原理之一(ngrx是Redux的实现),即ngrx存储是整个应用程序的single source of truth。在这里,我们说的是不同的话。这里我们说的是浏览器缓存是我们实体的唯一事实来源,而ngrx Store是其他所有事物的唯一事实来源(实际上比这还差一点:如果一个实体是可编辑的,那么Store必须在编辑时对此负责。
基础很简单。我们在实体的http响应上设置版本号和缓存时间:
X-Version: 23
Cache-Control: max-age=86400
当我们收到http响应时,我们将像以前一样处理它的主体,但是不会将其存储在任何地方。我们将其留给浏览器来为我们完成,如果我们第二次需要数据,我们只是简单地重新请求它,并且由于浏览器从其缓存中提供数据,因此数据几乎是即时到达的。
如果我们看到的实体版本已过时,则我们立即重新请求它,并确保通过在请求标头中设置Cache-Control: no-cache
来覆盖缓存。这样可以确保我们始终使用实体的当前版本。
this.http.get<T>(
url,
{...options, headers: {'Cache-Control': 'no-cache'}}
)
但是我们怎么知道一个版本已经过时了?幸运的是,我们的版本控制系统非常精细,因此我们不会经常获得更新。通过与我无关的Web套接字来更新当前版本号。因此请记住,我们是有福的,这种方法可能对您不起作用(至少在没有经过认真思考的情况下),并且计算机科学中只有two hard things:缓存无效并命名事物;-)
还需要保持警惕,因为我知道有几种方法可能会意外禁用浏览器缓存,这显然很可能会导致性能下降:
那么,如何解决这个问题(这不会让所有人高兴)? Ngrx 不能用作真正的缓存,但是浏览器可以!
答案 3 :(得分:0)
您可以执行类似的操作
friends$ = createEffect (() =>{
this.actions$.pipe(
.ofType(ListActions.LOAD)
.withLatestFrom(
this.store.select(fromSelectors.loadedList),
(action: fromList.Load, store: fromList.State) => store.friends
)
.switchMap((friends: Friend[]) => {
if (friends) {
return [new ListActions.Loaded(friends)];
}
return this.http
.get('/friendApi')
.map((friends: Friend[]) => new ListActions.Loaded(friends))
.catch(err => Observable.of(new ListActions.Failed()));
});
}
使用“ withLatestFrom”运算符,我们通过分派的动作使存储(已加载列表)状态生效,并检查列表是否被填充;调度现有列表,否则进行其余调用并更新我们在reducer中的商店。 有关详细答案,请参见this Medium post