RxJS Observable:发出数组中的每个特定更改

时间:2017-07-09 10:47:59

标签: typescript rxjs

我有一个用户ID列表,对于列表中的每个用户,我想要检索额外的信息。 所以我想知道列表何时更改,以及每个用户的信息何时更改。 例如:

  • 姓名:Anna,年龄:28
  • 姓名:Peter,年龄:23​​
  • 姓名:保罗,21岁

如果Anna的年龄发生变化,我希望能够更新列表,如果其他用户被添加到列表中,我也想跟踪它。

这就是我所做的:

private getUserData(userId:string):Observable<User>{...}

let userIds$:Observable<string[]> = getUserIds();

let users$ = userIds$.flatMap(x=>x)   //get the string[]
                     .map(userId => this.getUserData(chatId)) //for each ID get the data
                     .mergeAll();

users$.subscribe(x =>{console.log(x)});

这种做了我想要的,但我的问题是每次更新列表(添加元素或删除)时,列表中的每个元素都会再次订阅更改。 因此,例如,如果我在列表中添加2个元素,然后更新Anna的年龄,我会收到Anna 3次的对象。

对于我所读过的内容,switchMap可能会修复它,但我已经尝试过使用它,而且我还没有能够使它工作。

由于

1 个答案:

答案 0 :(得分:3)

欢迎使用Stack Overflow!

您需要的是发出一个值,该值是当前和上一个对象列表之间的差异。

使用lodash difference函数可以创建差异。

让我们假设数据结构如下:

[
  { name: 'Anna', age: 28 },
  { name: 'Peter', age: 23 },
  { name: 'Paul', age: 21 },
]

可以通过多种方式回答您的问题,但我提出的解决方案是:

  1. 将列表存储在一个不应该从外部访问的变量中。
  2. 创建一个BehaviorSubject,它会在更改时发出整个数组,并Observable发出差异。
  3. 创建将修改数组的函数,并告诉BehaviorSubject我们有一个新数组。
  4.   

    编辑:如果有人阅读此内容有创建完全反应式解决方案的雄心,请考虑使用scan运算符来包含   在一个流中具有完整功能的状态。 (剧透:你会重新发明redux什么不是坏事)。这里的例子是为了简单起见而写的。

    我不会尝试模拟您的实施(您从服务器API获取数据),但我会给您一个可以从中获取灵感的模式。

    const userList = {
      current: [],
      previous: [],
    };
    
    const userListChanged$ = new Rx.BehaviorSubject(userList.current);
    const userListDifference$ = userListChanged$.map(current => {
      return _.difference(current, userList.previous);
    });
    
    function currentToPrevious() {
      userList.previous = [].concat(userList.current);
    }
    
    function addUser(name, age) {
      currentToPrevious();
      userList.current.push({name, age});
      userListChanged$.next(userList.current);
    }
    
    function modifyUser(index, object) {
      currentToPrevious();
      userList.current[index] = Object.assign({}, userList.current[index], object);
      userListChanged$.next(userList.current);
    }
    
    userListChanged$.subscribe(value => console.log('list', value));
    userListDifference$.subscribe(value => console.log('diff', value));
    
    addUser('Peter', 29);
    addUser('Tom', 30);
    addUser('Anna', 21);
    modifyUser(2, { age: 20 });
    

    JSFiddle

    userListDifference$输出:

      

    [{name:&#39; Peter&#39;,age:29}]

         

    [{name:&#39; Tom&#39;,age:30}]

         

    [{name:&#39; Anna&#39;,age:21}]

         

    [{name:&#39; Anna&#39;,age:20}]

    userListChanged$输出:

      

    [{name:&#39; Peter&#39;,age:29}]

         

    [{name:&#39; Peter&#39;,年龄:29},{姓名:&#39; Tom&#39;,年龄:30}]

         

    [{name:&#39; Peter&#39;,年龄:29},{姓名:&#39; Tom&#39;,年龄:30},{姓名:&#39; Anna&#39;,年龄:21}]

         

    [{name:&#39; Peter&#39;,年龄:29},{姓名:&#39; Tom&#39;,年龄:30},{姓名:&#39; Anna&#39;,年龄:20}]