首先是又遇到了一些RXjs操作符,在这里简单的说一下。
首先是 combineLatest。
将其直接翻译过来就是结合最新的(observeble),那么结合一下下面这张图片就很容易理解了。
combineLatest结合作为参数传递的所有 Observables 的值。这是通过按顺序订阅每个 Observable 并在任何 Observable 发出时从每个 Observable 收集最新值的数组来完成的。因此,如果您将nObservable 传递给运算符,则返回的 Observable 将始终发出一个值数组,n其顺序与传递的 Observable 的顺序相对应(第一个 Observable 的值在第一位,依此类推)。
让我们再结合代码试一下
const firstTimer = Rx.Observable.timer(0, 1000); // emit 0, 1, 2... after every second, starting from now
const secondTimer = Rx.Observable.timer(500, 1000); // emit 0, 1, 2... after every second, starting 0,5s from now
const combinedTimers = Rx.Observable.combineLatest(firstTimer, secondTimer);
combinedTimers.subscribe(value => console.log(value));
// Logs
// [0, 0] after 0.5s
// [1, 0] after 1s
// [1, 1] after 1.5s
// [2, 1] after 2s
从此处我们也能更深刻地认识到,只有两个observble都触发时才会开始触发combineLatest。
项目中 用到了状态管理相关内容,下面来简单地说一下什么是状态模式,之前也有听老师讲过状态模式,但是由于没有找到实际代码所以对状态模式总是不理解。
当前项目的状态模式可以体现为如下形式
相当于状态模式就是代替了之前我们所用的服务层并且状态模式的特殊之处个人认为就体现在store的使用,store实现了将数据作为缓存直接存储在前台。
可能这么说不是很直接,下面再加上代码来说明一下。
我们目前可以简单地认为一个store只用来存储/操作一种状态,然后通过继承store类并将其设置为注射器来实现:
比如我们想对building实体进行管理
@Injectable()
export class BuildingStore extends Store<Building>{
export const BuildingActions = {
getUnit: 'getUnit'
}
static units(state: Unit) {
return state.units;
}
// 添加action注解与actions进行对接,使其可以由dispatch调用
// 我们可以发现此方法中虽然返回了observable但是data并没有返回,这是由于此方法将数据作为状态的更新存进了缓存(store)
@Action(taskActions.getUnit)
getUnit(state: Building, payload: number | string) {
return this.http.get(xxxurl).pipe(
.tap((data) => {
// 获取当前状态
const state = this.snapshot;
// 获取新状态
state.units = data.units;
// 更新状态
this.next(state);
})
}
}
然后我们可以在C层中这样调用
@Injectable()
export class BuildingComponent extends {
. . .
// 获取building对应的unit到缓存中
this.buildingStore
.dispatch(BuildingActions.getUnit, 1)
.subscribe(() => {
console.log('已获取units')
});
// 在此组件中获取units(去store中获取)
this.buildingStore.select(BuildingStore.units)
.subscribe(data => {
console.log("获取到的单元:");
console.log(units);
})
}
此外值得一提的是如果我们照上面代码操作的话this.buildingStore.select
会触发两次,第一次是旧数据,第二次是新数据。
猜测其过程为:
那么如果我们要从store中获取多种数据我们为了避免获取到旧的数据我们就可以和文章前面说到的combineLatest结合使用,从而保持数据的更新并且便于使用。
然后再来说一下本周遇到的一个奇怪的bug:
先说一下问题:
当我们更改时间时会弹出一个弹窗,将弹窗关闭后修改时间没有问题,但是点击右侧X号清空时间虽然向后台发出了请求但是前台显示没有实时更新——仍然是显示11月24,刷新页面后显示为空。
遇到这个问题期初是认为项目自身就存在的bug,但是将弹窗操作去除后发现一切正常,后来想是不是因为开启弹窗后由于弹窗组件没有正常销毁导致的。
于是在其销毁时进行打点并且在原组件中也进行打点判断各个地方的执行顺序有没有受到影响,但是打点后观察发现执行顺序和各个方法没有任何影响。并且销毁时间也符合预期。
后来询问老师后得知如果在子组件中改变了子组件的值也会发生这样的问题。
比如我们将XXX对象传给了弹窗组件,我们在弹窗组件中对其进行了更改就会发生问题,因为就想之前说到的那样,对象之间的传递都是传的地址,而angular并不推荐像这样改变父组件中的对象。
后来我又尝试既然直接传递对象有问题,那么将要传递的对象深拷贝后将拷贝后的对象传给弹窗组件应该就没问题了。
尝试之后发现还是不行,就算深拷贝后还是会有这样的问题。
后来老师调查后发现问题还是出在了状态模式中的store上。
比如我们还拿building举例,我们在父组件中根据buildingId获取了units,然后在子组件中再根据这个buildingId获取units,这两个地方都是获取缓存并进行操作就可能会出现问题,从而导致上面的问题。
要想更深入了解问题应该就需要进一步了解它缓存的机制——缓存是怎么存的?父组件,子组件缓存共享吗?什么时候清空缓存?缓存在什么情况下会出现问题?
这些问题都需要在之后的项目中进一步了解。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。